[Schmitzm-commits] r244 - in trunk: . src/appl/data src/appl/util src/junit/skrueger/i8n src/schmitzm/data src/schmitzm/data/event src/schmitzm/data/property src/schmitzm/data/resource/locales src/schmitzm/geotools src/schmitzm/geotools/feature src/schmitzm/geotools/feature/resource/locales src/schmitzm/geotools/grid src/schmitzm/geotools/gui src/schmitzm/geotools/gui/resource/locales src/schmitzm/geotools/io src/schmitzm/geotools/map/event src/schmitzm/geotools/styling src/schmitzm/io src/schmitzm/io/dyntxt src/schmitzm/jfree src/schmitzm/jfree/chart src/schmitzm/jfree/chart/renderer src/schmitzm/jfree/chart/selection src/schmitzm/jfree/chart/style src/schmitzm/jfree/feature src/schmitzm/jfree/feature/style src/schmitzm/jfree/resource/locales src/schmitzm/lang src/schmitzm/lang/resource/locales src/schmitzm/lang/tree src/schmitzm/swing src/schmitzm/swing/event src/schmitzm/swing/log4j src/schmitzm/swing/menu src/schmitzm/swing/resource/locales src/schmitzm/swing/table src/schmitzm/swing/tree src/schmitzm/temp src/schmitzm/xml src/skrueger src/skrueger/geotools src/skrueger/geotools/io src/skrueger/geotools/labelsearch src/skrueger/geotools/resource/locales src/skrueger/geotools/selection src/skrueger/i8n src/skrueger/swing

scm-commit@wald.intevation.org scm-commit at wald.intevation.org
Wed Jul 29 11:34:00 CEST 2009


Author: alfonx
Date: 2009-07-29 11:33:33 +0200 (Wed, 29 Jul 2009)
New Revision: 244

Added:
   trunk/license-lgpl.txt
Modified:
   trunk/src/appl/data/LateLoadable.java
   trunk/src/appl/data/LoadingException.java
   trunk/src/appl/util/RasterMetaData.java
   trunk/src/junit/skrueger/i8n/SwitchLanguageDialogTest.java
   trunk/src/schmitzm/data/AbstractReadableGrid.java
   trunk/src/schmitzm/data/AbstractWritableGrid.java
   trunk/src/schmitzm/data/DataUtil.java
   trunk/src/schmitzm/data/ObjectStructure.java
   trunk/src/schmitzm/data/ObjectStructureUtil.java
   trunk/src/schmitzm/data/RasterCalculator.java
   trunk/src/schmitzm/data/RasterFilter.java
   trunk/src/schmitzm/data/RasterOperationTree.java
   trunk/src/schmitzm/data/RasterOperationTreeParser.java
   trunk/src/schmitzm/data/ReadableGrid.java
   trunk/src/schmitzm/data/WritableGrid.java
   trunk/src/schmitzm/data/WritableGridArray.java
   trunk/src/schmitzm/data/WritableGridRaster.java
   trunk/src/schmitzm/data/event/AbstractObjectEvent.java
   trunk/src/schmitzm/data/event/AbstractObjectTraceable.java
   trunk/src/schmitzm/data/event/GeneralObjectChangeEvent.java
   trunk/src/schmitzm/data/event/Invoker.java
   trunk/src/schmitzm/data/event/NameChangeEvent.java
   trunk/src/schmitzm/data/event/ObjectChangeEvent.java
   trunk/src/schmitzm/data/event/ObjectCloseEvent.java
   trunk/src/schmitzm/data/event/ObjectEvent.java
   trunk/src/schmitzm/data/event/ObjectListener.java
   trunk/src/schmitzm/data/event/ObjectTraceable.java
   trunk/src/schmitzm/data/property/Access.java
   trunk/src/schmitzm/data/property/AccessViolationException.java
   trunk/src/schmitzm/data/property/Accessible.java
   trunk/src/schmitzm/data/property/DynamicProperties.java
   trunk/src/schmitzm/data/property/ListProperty.java
   trunk/src/schmitzm/data/property/ListPropertyReadAccess.java
   trunk/src/schmitzm/data/property/ListPropertyWriteAccess.java
   trunk/src/schmitzm/data/property/MatrixProperty.java
   trunk/src/schmitzm/data/property/Properties.java
   trunk/src/schmitzm/data/property/Property.java
   trunk/src/schmitzm/data/property/PropertyException.java
   trunk/src/schmitzm/data/property/PropertyReadAccess.java
   trunk/src/schmitzm/data/property/PropertySet.java
   trunk/src/schmitzm/data/property/PropertyType.java
   trunk/src/schmitzm/data/property/PropertyUtil.java
   trunk/src/schmitzm/data/property/PropertyWriteAccess.java
   trunk/src/schmitzm/data/property/ScalarProperty.java
   trunk/src/schmitzm/data/property/ValueProperty.java
   trunk/src/schmitzm/data/property/ValuePropertyAccessParameters.java
   trunk/src/schmitzm/data/property/ValuePropertyType.java
   trunk/src/schmitzm/data/resource/locales/DataResourceBundle.properties
   trunk/src/schmitzm/data/resource/locales/DataResourceBundle_de.properties
   trunk/src/schmitzm/geotools/FilterUtil.java
   trunk/src/schmitzm/geotools/GTUtil.java
   trunk/src/schmitzm/geotools/JTSUtil.java
   trunk/src/schmitzm/geotools/feature/AbstractAutoValueGenerator.java
   trunk/src/schmitzm/geotools/feature/AttributeFilter.java
   trunk/src/schmitzm/geotools/feature/AttributeTypeFilter.java
   trunk/src/schmitzm/geotools/feature/AutoValueGenerator.java
   trunk/src/schmitzm/geotools/feature/FeatureCollectionReader.java
   trunk/src/schmitzm/geotools/feature/FeatureOperationTree.java
   trunk/src/schmitzm/geotools/feature/FeatureOperationTreeFilter.java
   trunk/src/schmitzm/geotools/feature/FeatureOperationTreeParser.java
   trunk/src/schmitzm/geotools/feature/FeatureTableModel.java
   trunk/src/schmitzm/geotools/feature/FeatureTypeBuilderTableModel.java
   trunk/src/schmitzm/geotools/feature/FeatureTypeTableModel.java
   trunk/src/schmitzm/geotools/feature/FeatureUtil.java
   trunk/src/schmitzm/geotools/feature/NumberValueGenerator.java
   trunk/src/schmitzm/geotools/feature/resource/locales/FeatureResourceBundle.properties
   trunk/src/schmitzm/geotools/feature/resource/locales/FeatureResourceBundle_de.properties
   trunk/src/schmitzm/geotools/grid/GridStatistic.java
   trunk/src/schmitzm/geotools/grid/GridUtil.java
   trunk/src/schmitzm/geotools/grid/GridZoneStatistic.java
   trunk/src/schmitzm/geotools/grid/ReadableGridCoverage.java
   trunk/src/schmitzm/geotools/grid/WritableGridCoverage.java
   trunk/src/schmitzm/geotools/gui/CRSSelectionDialog.java
   trunk/src/schmitzm/geotools/gui/ColorMapTable.java
   trunk/src/schmitzm/geotools/gui/FeatureCollectionFilterPanel.java
   trunk/src/schmitzm/geotools/gui/FeatureCollectionFrame.java
   trunk/src/schmitzm/geotools/gui/FeatureCollectionTableModel.java
   trunk/src/schmitzm/geotools/gui/FeatureFilterPanel.java
   trunk/src/schmitzm/geotools/gui/FeatureInputOption.java
   trunk/src/schmitzm/geotools/gui/FeatureLayerFilterDialog.java
   trunk/src/schmitzm/geotools/gui/FeatureTablePane.java
   trunk/src/schmitzm/geotools/gui/FeatureTypeInputOption.java
   trunk/src/schmitzm/geotools/gui/GeoMapPane.java
   trunk/src/schmitzm/geotools/gui/GeoPositionLabel.java
   trunk/src/schmitzm/geotools/gui/GeotoolsGUIUtil.java
   trunk/src/schmitzm/geotools/gui/GridPanel.java
   trunk/src/schmitzm/geotools/gui/JEditorPane.java
   trunk/src/schmitzm/geotools/gui/JEditorToolBar.java
   trunk/src/schmitzm/geotools/gui/JMapPane.java
   trunk/src/schmitzm/geotools/gui/LayeredEditorFrame.java
   trunk/src/schmitzm/geotools/gui/LayeredMapFrame.java
   trunk/src/schmitzm/geotools/gui/LayeredMapPane.java
   trunk/src/schmitzm/geotools/gui/MapActionControlPane.java
   trunk/src/schmitzm/geotools/gui/MapContextControlPane.java
   trunk/src/schmitzm/geotools/gui/MapPaneStatusBar.java
   trunk/src/schmitzm/geotools/gui/MouseSelectionTracker.java
   trunk/src/schmitzm/geotools/gui/RasterPositionLabel.java
   trunk/src/schmitzm/geotools/gui/ScalePane.java
   trunk/src/schmitzm/geotools/gui/ScalePanel.java
   trunk/src/schmitzm/geotools/gui/SelectableFeatureTablePane.java
   trunk/src/schmitzm/geotools/gui/StyleToolBar.java
   trunk/src/schmitzm/geotools/gui/resource/locales/GTResourceBundle.properties
   trunk/src/schmitzm/geotools/gui/resource/locales/GTResourceBundle_de.properties
   trunk/src/schmitzm/geotools/gui/resource/locales/GTResourceBundle_fr.properties
   trunk/src/schmitzm/geotools/io/GeoExportUtil.java
   trunk/src/schmitzm/geotools/io/GeoImportUtil.java
   trunk/src/schmitzm/geotools/map/event/FeatureModifiedEvent.java
   trunk/src/schmitzm/geotools/map/event/FeatureSelectedEvent.java
   trunk/src/schmitzm/geotools/map/event/GeneralSelectionEvent.java
   trunk/src/schmitzm/geotools/map/event/GridCoverageSelectedEvent.java
   trunk/src/schmitzm/geotools/map/event/GridCoverageValueSelectedEvent.java
   trunk/src/schmitzm/geotools/map/event/JEditorPaneEvent.java
   trunk/src/schmitzm/geotools/map/event/JMapPaneEvent.java
   trunk/src/schmitzm/geotools/map/event/JMapPaneListener.java
   trunk/src/schmitzm/geotools/map/event/LayerEditCanceledEvent.java
   trunk/src/schmitzm/geotools/map/event/LayerEditFinishedEvent.java
   trunk/src/schmitzm/geotools/map/event/LayerEditStartedEvent.java
   trunk/src/schmitzm/geotools/map/event/MapAreaChangedEvent.java
   trunk/src/schmitzm/geotools/map/event/MapContextSynchronizer.java
   trunk/src/schmitzm/geotools/map/event/MapLayerAdapter.java
   trunk/src/schmitzm/geotools/map/event/MapLayerListAdapter.java
   trunk/src/schmitzm/geotools/map/event/ObjectSelectionEvent.java
   trunk/src/schmitzm/geotools/map/event/ScaleChangedEvent.java
   trunk/src/schmitzm/geotools/styling/ColorMapManager.java
   trunk/src/schmitzm/geotools/styling/StylingUtil.java
   trunk/src/schmitzm/io/BinaryInputBuffer.java
   trunk/src/schmitzm/io/BinaryInputStream.java
   trunk/src/schmitzm/io/BinaryUtil.java
   trunk/src/schmitzm/io/CombinedInputStream.java
   trunk/src/schmitzm/io/FileInputStream.java
   trunk/src/schmitzm/io/FileOutputStream.java
   trunk/src/schmitzm/io/IOUtil.java
   trunk/src/schmitzm/io/InputBuffer.java
   trunk/src/schmitzm/io/LimitedInputStream.java
   trunk/src/schmitzm/io/TokenInputStream.java
   trunk/src/schmitzm/io/dyntxt/DynamicBlock.java
   trunk/src/schmitzm/io/dyntxt/DynamicElement.java
   trunk/src/schmitzm/io/dyntxt/DynamicField.java
   trunk/src/schmitzm/io/dyntxt/DynamicInputProvider.java
   trunk/src/schmitzm/io/dyntxt/DynamicLoop.java
   trunk/src/schmitzm/io/dyntxt/DynamicTextGenerator.java
   trunk/src/schmitzm/io/dyntxt/StaticText.java
   trunk/src/schmitzm/jfree/DatasetMetaDataGroup.java
   trunk/src/schmitzm/jfree/JFreeChartUtil.java
   trunk/src/schmitzm/jfree/chart/ChartMouseSelectionTracker.java
   trunk/src/schmitzm/jfree/chart/SelectableChartPanel.java
   trunk/src/schmitzm/jfree/chart/renderer/SelectionRenderer.java
   trunk/src/schmitzm/jfree/chart/renderer/SelectionXYLineAndShapeRenderer.java
   trunk/src/schmitzm/jfree/chart/selection/AbstractDatasetSelectionModel.java
   trunk/src/schmitzm/jfree/chart/selection/DatasetSelectionChangeEvent.java
   trunk/src/schmitzm/jfree/chart/selection/DatasetSelectionListener.java
   trunk/src/schmitzm/jfree/chart/selection/DatasetSelectionModel.java
   trunk/src/schmitzm/jfree/chart/selection/DatasetSelectionModelProvider.java
   trunk/src/schmitzm/jfree/chart/selection/SeriesDatasetSelectionModel.java
   trunk/src/schmitzm/jfree/chart/style/AbstractChartStyle.java
   trunk/src/schmitzm/jfree/chart/style/BasicChartStyle.java
   trunk/src/schmitzm/jfree/chart/style/ChartAxisStyle.java
   trunk/src/schmitzm/jfree/chart/style/ChartLabelStyle.java
   trunk/src/schmitzm/jfree/chart/style/ChartPlotStyle.java
   trunk/src/schmitzm/jfree/chart/style/ChartRendererStyle.java
   trunk/src/schmitzm/jfree/chart/style/ChartStyle.java
   trunk/src/schmitzm/jfree/chart/style/ChartStyleUtil.java
   trunk/src/schmitzm/jfree/chart/style/ChartStyleXMLFactory.java
   trunk/src/schmitzm/jfree/chart/style/ChartType.java
   trunk/src/schmitzm/jfree/chart/style/ScatterChartStyle.java
   trunk/src/schmitzm/jfree/feature/Feature2DatasetMapping.java
   trunk/src/schmitzm/jfree/feature/Feature2SeriesDatasetMapping.java
   trunk/src/schmitzm/jfree/feature/FeatureDatasetMetaData.java
   trunk/src/schmitzm/jfree/feature/FeatureDatasetSelectionModel.java
   trunk/src/schmitzm/jfree/feature/FeatureSeriesDatasetSelectionModel.java
   trunk/src/schmitzm/jfree/feature/style/FeatureBasicChartStyle.java
   trunk/src/schmitzm/jfree/feature/style/FeatureChartStyle.java
   trunk/src/schmitzm/jfree/feature/style/FeatureChartStyleXMLFactory.java
   trunk/src/schmitzm/jfree/feature/style/FeatureChartUtil.java
   trunk/src/schmitzm/jfree/feature/style/FeatureScatterChartStyle.java
   trunk/src/schmitzm/jfree/resource/locales/JFreeResourceBundle.properties
   trunk/src/schmitzm/jfree/resource/locales/JFreeResourceBundle_de.properties
   trunk/src/schmitzm/lang/AbstractNamedObject.java
   trunk/src/schmitzm/lang/AlreadyHandledException.java
   trunk/src/schmitzm/lang/ComparableObject.java
   trunk/src/schmitzm/lang/DefaultComparator.java
   trunk/src/schmitzm/lang/DuplicateException.java
   trunk/src/schmitzm/lang/HashtableResourceBundle.java
   trunk/src/schmitzm/lang/HashtableWithCollisionList.java
   trunk/src/schmitzm/lang/Indent.java
   trunk/src/schmitzm/lang/LangUtil.java
   trunk/src/schmitzm/lang/LimitedVector.java
   trunk/src/schmitzm/lang/LocaleComparator.java
   trunk/src/schmitzm/lang/MultiDimArray.java
   trunk/src/schmitzm/lang/NamedObject.java
   trunk/src/schmitzm/lang/OperationCanceledException.java
   trunk/src/schmitzm/lang/PushbackStringTokenizer.java
   trunk/src/schmitzm/lang/ResourceProvider.java
   trunk/src/schmitzm/lang/SortableVector.java
   trunk/src/schmitzm/lang/StepThread.java
   trunk/src/schmitzm/lang/WorkingThread.java
   trunk/src/schmitzm/lang/WorkingThreadAdapter.java
   trunk/src/schmitzm/lang/WorkingThreadListener.java
   trunk/src/schmitzm/lang/resource/locales/LangResourceBundle.properties
   trunk/src/schmitzm/lang/resource/locales/LangResourceBundle_de.properties
   trunk/src/schmitzm/lang/tree/BinaryTreeNode.java
   trunk/src/schmitzm/lang/tree/OperationTree.java
   trunk/src/schmitzm/lang/tree/OperationTreeParser.java
   trunk/src/schmitzm/lang/tree/TreeNode.java
   trunk/src/schmitzm/swing/BooleanInputOption.java
   trunk/src/schmitzm/swing/BrowseInputOption.java
   trunk/src/schmitzm/swing/ButtonGroup.java
   trunk/src/schmitzm/swing/CaptionsChangeable.java
   trunk/src/schmitzm/swing/CaptionsChangeablePanel.java
   trunk/src/schmitzm/swing/CircleIcon.java
   trunk/src/schmitzm/swing/ColorInputOption.java
   trunk/src/schmitzm/swing/Compass.java
   trunk/src/schmitzm/swing/ExceptionDialog.java
   trunk/src/schmitzm/swing/ExpansionBar.java
   trunk/src/schmitzm/swing/FileInputOption.java
   trunk/src/schmitzm/swing/InputCompass.java
   trunk/src/schmitzm/swing/InputOption.java
   trunk/src/schmitzm/swing/JPanel.java
   trunk/src/schmitzm/swing/ManualInputOption.java
   trunk/src/schmitzm/swing/MultiSplitPane.java
   trunk/src/schmitzm/swing/MultipleOptionPane.java
   trunk/src/schmitzm/swing/ObjectDisplayContainer.java
   trunk/src/schmitzm/swing/OperationTreePanel.java
   trunk/src/schmitzm/swing/RotationSpinnerNumberModel.java
   trunk/src/schmitzm/swing/SelectableJTable.java
   trunk/src/schmitzm/swing/SelectionInputOption.java
   trunk/src/schmitzm/swing/SelectionPreservingCaret.java
   trunk/src/schmitzm/swing/SliderSpinnerPanel.java
   trunk/src/schmitzm/swing/SortableJTable.java
   trunk/src/schmitzm/swing/SpringUtilities.java
   trunk/src/schmitzm/swing/StatusDialog.java
   trunk/src/schmitzm/swing/StoplightContainer.java
   trunk/src/schmitzm/swing/SwingUtil.java
   trunk/src/schmitzm/swing/SwingWorker.java
   trunk/src/schmitzm/swing/TextAreaPrintStream.java
   trunk/src/schmitzm/swing/ToolTipComboBoxRenderer.java
   trunk/src/schmitzm/swing/TreeSelectionDialog.java
   trunk/src/schmitzm/swing/event/InputOptionAdapter.java
   trunk/src/schmitzm/swing/event/InputOptionListener.java
   trunk/src/schmitzm/swing/event/MouseAdapter.java
   trunk/src/schmitzm/swing/event/PopupMenuListener.java
   trunk/src/schmitzm/swing/event/PropertyChangeEmitter.java
   trunk/src/schmitzm/swing/event/WindowEventConnector.java
   trunk/src/schmitzm/swing/log4j/LoggerConfigurationTableModel.java
   trunk/src/schmitzm/swing/log4j/LoggerFrame.java
   trunk/src/schmitzm/swing/menu/ActionStructure.java
   trunk/src/schmitzm/swing/menu/ConnectedPopupMenu.java
   trunk/src/schmitzm/swing/menu/ObjectMenuItem.java
   trunk/src/schmitzm/swing/menu/ObjectSubMenu.java
   trunk/src/schmitzm/swing/resource/locales/SwingResourceBundle.properties
   trunk/src/schmitzm/swing/resource/locales/SwingResourceBundle_de.properties
   trunk/src/schmitzm/swing/resource/locales/SwingResourceBundle_fr.properties
   trunk/src/schmitzm/swing/table/AbstractMutableTableModel.java
   trunk/src/schmitzm/swing/table/AbstractTableModel.java
   trunk/src/schmitzm/swing/table/ColorEditor.java
   trunk/src/schmitzm/swing/table/ColorRenderer.java
   trunk/src/schmitzm/swing/table/ColorsRenderer.java
   trunk/src/schmitzm/swing/table/ComponentRenderer.java
   trunk/src/schmitzm/swing/table/MutableTable.java
   trunk/src/schmitzm/swing/table/MutableTableModel.java
   trunk/src/schmitzm/swing/table/PipedTableModel.java
   trunk/src/schmitzm/swing/table/SelectionTableModel.java
   trunk/src/schmitzm/swing/table/TableComponentMouseListener.java
   trunk/src/schmitzm/swing/tree/ContentNode.java
   trunk/src/schmitzm/swing/tree/EditableNode.java
   trunk/src/schmitzm/swing/tree/EmptyInnerNode.java
   trunk/src/schmitzm/swing/tree/EmptyNode.java
   trunk/src/schmitzm/temp/BaseTypeUtil.java
   trunk/src/schmitzm/xml/XMLUtil.java
   trunk/src/skrueger/AttributeMetaData.java
   trunk/src/skrueger/AttributeMetaDataAttributeTypeFilter.java
   trunk/src/skrueger/RasterLegendData.java
   trunk/src/skrueger/geotools/AbstractStyledLayer.java
   trunk/src/skrueger/geotools/AttributeTableJDialog.java
   trunk/src/skrueger/geotools/LegendIconFeatureRenderer.java
   trunk/src/skrueger/geotools/MapContextManagerInterface.java
   trunk/src/skrueger/geotools/MapPaneToolBar.java
   trunk/src/skrueger/geotools/MapView.java
   trunk/src/skrueger/geotools/StyledFS.java
   trunk/src/skrueger/geotools/StyledFeatureCollection.java
   trunk/src/skrueger/geotools/StyledFeatureCollectionInterface.java
   trunk/src/skrueger/geotools/StyledFeatureCollectionTableModel.java
   trunk/src/skrueger/geotools/StyledFeatureSourceInterface.java
   trunk/src/skrueger/geotools/StyledFeaturesInterface.java
   trunk/src/skrueger/geotools/StyledGridCoverage.java
   trunk/src/skrueger/geotools/StyledGridCoverageInterface.java
   trunk/src/skrueger/geotools/StyledGridCoverageReader.java
   trunk/src/skrueger/geotools/StyledGridCoverageReaderInterface.java
   trunk/src/skrueger/geotools/StyledLayerInterface.java
   trunk/src/skrueger/geotools/StyledLayerStyle.java
   trunk/src/skrueger/geotools/StyledLayerUtil.java
   trunk/src/skrueger/geotools/StyledRasterInterface.java
   trunk/src/skrueger/geotools/ZoomRestrictableGridInterface.java
   trunk/src/skrueger/geotools/io/GeoImportUtilURL.java
   trunk/src/skrueger/geotools/labelsearch/LabelSearch.java
   trunk/src/skrueger/geotools/labelsearch/SearchMapDialog.java
   trunk/src/skrueger/geotools/labelsearch/SearchResult.java
   trunk/src/skrueger/geotools/labelsearch/SearchResultFeature.java
   trunk/src/skrueger/geotools/labelsearch/SearchResultTableModel.java
   trunk/src/skrueger/geotools/labelsearch/Snippet.java
   trunk/src/skrueger/geotools/labelsearch/labelsearch.properties
   trunk/src/skrueger/geotools/labelsearch/labelsearch_de.properties
   trunk/src/skrueger/geotools/labelsearch/labelsearch_fr.properties
   trunk/src/skrueger/geotools/resource/locales/mapPaneToolbar.properties
   trunk/src/skrueger/geotools/resource/locales/mapPaneToolbar_de.properties
   trunk/src/skrueger/geotools/resource/locales/mapPaneToolbar_fr.properties
   trunk/src/skrueger/geotools/selection/ChartSelectionSynchronizer.java
   trunk/src/skrueger/geotools/selection/FeatureMapLayerSelectionSynchronizer.java
   trunk/src/skrueger/geotools/selection/StyledFeatureLayerSelectionModel.java
   trunk/src/skrueger/geotools/selection/StyledLayerSelectionEvent.java
   trunk/src/skrueger/geotools/selection/StyledLayerSelectionModel.java
   trunk/src/skrueger/geotools/selection/StyledLayerSelectionModelSynchronizer.java
   trunk/src/skrueger/geotools/selection/TableSelectionSynchronizer.java
   trunk/src/skrueger/i8n/I8NUtil.java
   trunk/src/skrueger/i8n/SwitchLanguageDialog.java
   trunk/src/skrueger/i8n/Translation.java
   trunk/src/skrueger/swing/CancelButton.java
   trunk/src/skrueger/swing/OkButton.java
   trunk/src/skrueger/swing/TranslationAskJDialog.java
   trunk/src/skrueger/swing/TranslationEditJPanel.java
   trunk/src/skrueger/swing/TranslationJTextField.java
Log:
* Updated all .java and .properties headers with a recent LGPL 3.0 and a link to the project webpage.

Added: trunk/license-lgpl.txt
===================================================================
--- trunk/license-lgpl.txt	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/license-lgpl.txt	2009-07-29 09:33:33 UTC (rev 244)
@@ -0,0 +1,167 @@
+		   GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+
+  This version of the GNU Lesser General Public License incorporates
+the terms and conditions of version 3 of the GNU General Public
+License, supplemented by the additional permissions listed below.
+
+  0. Additional Definitions.
+
+  As used herein, "this License" refers to version 3 of the GNU Lesser
+General Public License, and the "GNU GPL" refers to version 3 of the GNU
+General Public License.
+
+  "The Library" refers to a covered work governed by this License,
+other than an Application or a Combined Work as defined below.
+
+  An "Application" is any work that makes use of an interface provided
+by the Library, but which is not otherwise based on the Library.
+Defining a subclass of a class defined by the Library is deemed a mode
+of using an interface provided by the Library.
+
+  A "Combined Work" is a work produced by combining or linking an
+Application with the Library.  The particular version of the Library
+with which the Combined Work was made is also called the "Linked
+Version".
+
+  The "Minimal Corresponding Source" for a Combined Work means the
+Corresponding Source for the Combined Work, excluding any source code
+for portions of the Combined Work that, considered in isolation, are
+based on the Application, and not on the Linked Version.
+
+  The "Corresponding Application Code" for a Combined Work means the
+object code and/or source code for the Application, including any data
+and utility programs needed for reproducing the Combined Work from the
+Application, but excluding the System Libraries of the Combined Work.
+
+  1. Exception to Section 3 of the GNU GPL.
+
+  You may convey a covered work under sections 3 and 4 of this License
+without being bound by section 3 of the GNU GPL.
+
+  2. Conveying Modified Versions.
+
+  If you modify a copy of the Library, and, in your modifications, a
+facility refers to a function or data to be supplied by an Application
+that uses the facility (other than as an argument passed when the
+facility is invoked), then you may convey a copy of the modified
+version:
+
+   a) under this License, provided that you make a good faith effort to
+   ensure that, in the event an Application does not supply the
+   function or data, the facility still operates, and performs
+   whatever part of its purpose remains meaningful, or
+
+   b) under the GNU GPL, with none of the additional permissions of
+   this License applicable to that copy.
+
+  3. Object Code Incorporating Material from Library Header Files.
+
+  The object code form of an Application may incorporate material from
+a header file that is part of the Library.  You may convey such object
+code under terms of your choice, provided that, if the incorporated
+material is not limited to numerical parameters, data structure
+layouts and accessors, or small macros, inline functions and templates
+(ten or fewer lines in length), you do both of the following:
+
+   a) Give prominent notice with each copy of the object code that the
+   Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the object code with a copy of the GNU GPL and this license
+   document.
+
+  4. Combined Works.
+
+  You may convey a Combined Work under terms of your choice that,
+taken together, effectively do not restrict modification of the
+portions of the Library contained in the Combined Work and reverse
+engineering for debugging such modifications, if you also do each of
+the following:
+
+   a) Give prominent notice with each copy of the Combined Work that
+   the Library is used in it and that the Library and its use are
+   covered by this License.
+
+   b) Accompany the Combined Work with a copy of the GNU GPL and this license
+   document.
+
+   c) For a Combined Work that displays copyright notices during
+   execution, include the copyright notice for the Library among
+   these notices, as well as a reference directing the user to the
+   copies of the GNU GPL and this license document.
+
+   d) Do one of the following:
+
+       0) Convey the Minimal Corresponding Source under the terms of this
+       License, and the Corresponding Application Code in a form
+       suitable for, and under terms that permit, the user to
+       recombine or relink the Application with a modified version of
+       the Linked Version to produce a modified Combined Work, in the
+       manner specified by section 6 of the GNU GPL for conveying
+       Corresponding Source.
+
+       1) Use a suitable shared library mechanism for linking with the
+       Library.  A suitable mechanism is one that (a) uses at run time
+       a copy of the Library already present on the user's computer
+       system, and (b) will operate properly with a modified version
+       of the Library that is interface-compatible with the Linked
+       Version.
+
+   e) Provide Installation Information, but only if you would otherwise
+   be required to provide such information under section 6 of the
+   GNU GPL, and only to the extent that such information is
+   necessary to install and execute a modified version of the
+   Combined Work produced by recombining or relinking the
+   Application with a modified version of the Linked Version. (If
+   you use option 4d0, the Installation Information must accompany
+   the Minimal Corresponding Source and Corresponding Application
+   Code. If you use option 4d1, you must provide the Installation
+   Information in the manner specified by section 6 of the GNU GPL
+   for conveying Corresponding Source.)
+
+  5. Combined Libraries.
+
+  You may place library facilities that are a work based on the
+Library side by side in a single library together with other library
+facilities that are not Applications and are not covered by this
+License, and convey such a combined library under terms of your
+choice, if you do both of the following:
+
+   a) Accompany the combined library with a copy of the same work based
+   on the Library, uncombined with any other library facilities,
+   conveyed under the terms of this License.
+
+   b) Give prominent notice with the combined library that part of it
+   is a work based on the Library, and explaining where to find the
+   accompanying uncombined form of the same work.
+
+  6. Revised Versions of the GNU Lesser General Public License.
+
+  The Free Software Foundation may publish revised and/or new versions
+of the GNU Lesser General Public License from time to time. Such new
+versions will be similar in spirit to the present version, but may
+differ in detail to address new problems or concerns.
+
+  Each version is given a distinguishing version number. If the
+Library as you received it specifies that a certain numbered version
+of the GNU Lesser General Public License "or any later version"
+applies to it, you have the option of following the terms and
+conditions either of that published version or of any later version
+published by the Free Software Foundation. If the Library as you
+received it does not specify a version number of the GNU Lesser
+General Public License, you may choose any version of the GNU Lesser
+General Public License ever published by the Free Software Foundation.
+
+  If the Library as you received it specifies that a proxy can decide
+whether future versions of the GNU Lesser General Public License shall
+apply, that proxy's public statement of acceptance of any version is
+permanent authorization for you to choose that version for the
+Library.
+
+                     END OF TERMS AND CONDITIONS
\ No newline at end of file


Property changes on: trunk/license-lgpl.txt
___________________________________________________________________
Name: svn:mime-type
   + text/plain
Name: svn:keywords
   + Id
Name: svn:eol-style
   + native

Modified: trunk/src/appl/data/LateLoadable.java
===================================================================
--- trunk/src/appl/data/LateLoadable.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/appl/data/LateLoadable.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,40 +1,69 @@
-package appl.data;
-
-import schmitzm.data.WritableGrid;
-
-/**
- * Defines the base functionality of late loading. Late loading means that the
- * data is loaded into memory only when it is accessed (for example by
- * <code>getRasterSample(..)</code>-Methods when implemented for
- * {@link WritableGrid}s). Notice that this class can be used with any datatype
- * (not only grids).
- * 
- * @author Dominik Appl
- */
-public interface LateLoadable {
-	/**
-	 * Answers if the data type supports late loading
-	 * 
-	 * @return true, if late loading is supported
-	 */
-	public boolean isLateLoadable();
-
-	/**
-	 * Loads the Data into the memory if this function supported. Else it should
-	 * be already loaded
-	 * 
-	 * @throws LoadingException
-	 *             if the loading fails
-	 */
-	public void loadData() throws LoadingException;
-
-	/**
-	 * Unloads the Data onto disk or into nirvana, depending on implementation.
-	 * Or does nothing, if late loading is not supported. <b>NOTICE</b>:
-	 * UNLOADING DOES NOT MEAN, THAT DATA IS WRITTEN BACK TO THE SOURCE. It may
-	 * be stored in a temporary file for later loading/export, depending on
-	 * implementation.
-	 */
-	public void unloadData();
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package appl.data;
+
+import schmitzm.data.WritableGrid;
+
+/**
+ * Defines the base functionality of late loading. Late loading means that the
+ * data is loaded into memory only when it is accessed (for example by
+ * <code>getRasterSample(..)</code>-Methods when implemented for
+ * {@link WritableGrid}s). Notice that this class can be used with any datatype
+ * (not only grids).
+ * 
+ * @author Dominik Appl
+ */
+public interface LateLoadable {
+	/**
+	 * Answers if the data type supports late loading
+	 * 
+	 * @return true, if late loading is supported
+	 */
+	public boolean isLateLoadable();
+
+	/**
+	 * Loads the Data into the memory if this function supported. Else it should
+	 * be already loaded
+	 * 
+	 * @throws LoadingException
+	 *             if the loading fails
+	 */
+	public void loadData() throws LoadingException;
+
+	/**
+	 * Unloads the Data onto disk or into nirvana, depending on implementation.
+	 * Or does nothing, if late loading is not supported. <b>NOTICE</b>:
+	 * UNLOADING DOES NOT MEAN, THAT DATA IS WRITTEN BACK TO THE SOURCE. It may
+	 * be stored in a temporary file for later loading/export, depending on
+	 * implementation.
+	 */
+	public void unloadData();
+
+}

Modified: trunk/src/appl/data/LoadingException.java
===================================================================
--- trunk/src/appl/data/LoadingException.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/appl/data/LoadingException.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,28 +1,57 @@
-package appl.data;
-
-/**
- * Thrown when the data loading from some source fails.
- * 
- * @author Dominik Appl
- */
-public class LoadingException extends Exception {
-
-	String loadSource;
-
-	/**
-	 * Creates a new Exception with the name of the Source from which the
-	 * loading failed
-	 */
-	public LoadingException(String message, Object loadSource) {
-		super(message);
-		this.loadSource = loadSource.toString();
-
-	}
-
-	/**
-	 * @return the name of the Source from which the loading failed
-	 */
-	public String getLoadSource() {
-		return loadSource;
-	}
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package appl.data;
+
+/**
+ * Thrown when the data loading from some source fails.
+ * 
+ * @author Dominik Appl
+ */
+public class LoadingException extends Exception {
+
+	String loadSource;
+
+	/**
+	 * Creates a new Exception with the name of the Source from which the
+	 * loading failed
+	 */
+	public LoadingException(String message, Object loadSource) {
+		super(message);
+		this.loadSource = loadSource.toString();
+
+	}
+
+	/**
+	 * @return the name of the Source from which the loading failed
+	 */
+	public String getLoadSource() {
+		return loadSource;
+	}
+}

Modified: trunk/src/appl/util/RasterMetaData.java
===================================================================
--- trunk/src/appl/util/RasterMetaData.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/appl/util/RasterMetaData.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,236 +1,265 @@
-package appl.util;
-
-import java.awt.image.DataBuffer;
-import java.io.Serializable;
-
-import org.geotools.referencing.crs.DefaultGeographicCRS;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-
-import schmitzm.data.WritableGrid;
-
-/**
- * Simple immutable class that encapsulates raster metadata, 
- * especially the MetaData of a {@link WritableGrid}. 
- * Just a constructor and getters
- * on the fields.
- * 
- * <br> 
- * @see WritableGrid for details on the variable description
- *
- * @author Dominik Appl
- */
-public final class RasterMetaData implements Serializable {
-
-    int width = 0;
-
-    int height = 0;
-
-    int minX = 0;
-
-    int minY = 0;
-
-    double realWidth = 0;
-
-    double realHeight = 0;
-
-    int dataType = DataBuffer.TYPE_UNDEFINED;
-
-    double x = 0.0;
-
-    double y = 0.0;
-
-    CoordinateReferenceSystem crs = null;
-
-
-        /**
-         * @return Returns the CRS of the raster
-         */
-        public final CoordinateReferenceSystem getCoordinateReferenceSystem() {
-          return crs;
-        }
-
-	/**
-	 * @return Returns the height in cells
-	 */
-	public final int getHeight() {
-		return height;
-	}
-
-	/**
-	 * @return Returns the width in cells.
-	 */
-	public final int getWidth() {
-		return width;
-	}
-
-	/**
-	 * @return Returns the dataType.
-	 */
-	public final int getDataType() {
-		return dataType;
-	}
-
-	/**
-	 * @return Returns minX (used to indicate a start index)
-	 * @see WritableGrid#getMinX()
-	 */
-	public final int getMinX() {
-		return minX;
-	}
-
-	/**
-	 * @return Returns the minY ((used to indicate a start index)
-	 * @see WritableGrid#getMinY()
-	 */
-	public final int getMinY() {
-		return minY;
-	}
-
-	/**
-	 * @return Returns the realHeight.
-	 */
-	public final double getRealHeight() {
-		return realHeight;
-	}
-
-	/**
-	 * @return Returns the realWidth.
-	 */
-	public final double getRealWidth() {
-		return realWidth;
-	}
-
-	/**
-	 * @return Returns the (geographic) x-coordinate
-	 */
-	public final double getX() {
-		return x;
-	}
-
-
-	/**
-	 * @return Returns  the (geographic) y-coordinate
-	 */
-	public final double getY() {
-		return y;
-	}
-
-	/**
-	 * @param dataType the datatype
-	 * @param gridWidth the width of the grid (in cells)
-	 * @param gridHeight the height of the grid (in cells)
-	 * @param minX the minX (used to indicate a start index)
-	 * @param minY the minY (used to indicate a start index)
-	 * @param realWidth the real width
-	 * @param realHeight the real height
-	 * @param x the (geographic) x-coordinate
-	 * @param y the (geographic) y-coordinate
-     * @param crs the {@link CoordinateReferenceSystem}. Use null for DefaultCRS (WGS84)
-     * 
-     * @see WritableGrid
-	 */
-	public RasterMetaData(int dataType, int gridWidth, int gridHeight,
-			int minX, int minY, double x, double y, double realWidth,
-			double realHeight, CoordinateReferenceSystem crs) {
-		this.width = gridWidth;
-		this.height = gridHeight;
-		this.minX = minX;
-		this.minY = minY;
-		this.realWidth = realWidth;
-		this.realHeight = realHeight;
-		this.dataType = dataType;
-		this.x = x;
-		this.y = y;
-		this.crs = (crs == null) ? DefaultGeographicCRS.WGS84 : crs;
-        
-	}
-
-	/**
-	 * Constructs a RasterMetaData Object. The values of the real height/ width 
-	 * are calculated out of the cellsize. The cells are assumed to be squares.
-	 * 
-	 * @param dataType the datatype
-	 * @param gridWidth the width of the grid (in cells)
-	 * @param gridHeight the height of the grid (in cells)
-	 * @param minX the minX (used to indicate a start index)
-	 * @param minY the minY (used to indicate a start index)
-	 * @param x the (geographic) x-coordinate
-	 * @param y the (geographic) y-coordinate
-	 * @param cellSize the real size of one cell
-     * @param crs the {@link CoordinateReferenceSystem}, use null for default CRS (WGS84)
-	 */
-	public RasterMetaData(int dataType,  int gridWidth, int gridHeight,
-			int minX, int minY, double x, double y, double cellSize, CoordinateReferenceSystem crs) {
-
-		this(dataType, gridWidth, gridHeight, minX, minY, x, y, gridWidth
-				* cellSize, gridHeight * cellSize,crs);
-	}
-
-	/**
-	 * Constructs a RasterMetaDataObject out of the given Grid
-	 * @param w the source grid
-	 */
-	public RasterMetaData(WritableGrid w) {
-        super();
-        this.width = w.getWidth();
-        this.height = w.getHeight();
-        this.minX = w.getMinX();
-        this.minY = w.getMinY();
-        this.realWidth = w.getRealWidth();
-        this.realHeight = w.getRealHeight();
-        this.dataType = w.getSampleType();
-        this.x = w.getX();
-        this.y = w.getY();
-        this.crs = w.getCoordinateReferenceSystem();
-    }
-
-	/**
-	 * needed for serialization
-	 */
-	private RasterMetaData() {
-	 this(0,0,0,0,0,0,0,0,0,null);
-	}
-
-	/**
-	 * @return the real width of a raster cell
-	 */
-	public final double getCellWidth() {
-		return getRealWidth() / getWidth();
-	}
-
-	/**
-	 * Checks if the given RasterMetaData object has the same values.
-	 *
-	 * @param rasterMeta must be a RasterMetaDataObject! Else ClassCastException will be thrown.
-	 * @return true, if all values are the same
-	 * @see java.lang.Object#equals(java.lang.Object)
-	 */
-	@Override
-	public boolean equals(Object rasterMeta) {
-		RasterMetaData r = (RasterMetaData) rasterMeta;
-        return (
-        		this.width == r.getWidth() &&
-        		this.height == r.getHeight() &&
-        		this.minX == r.getMinX() &&
-        		this.minY == r.getMinY() &&
-        		this.realWidth == r.getRealWidth() &&
-        		this.realHeight == r.getRealHeight() &&
-        		this.dataType == r.getDataType() &&
-        		this.x == r.getX() &&
-        		this.y == r.getY()
-        		);
-	}
-
-	/**
-	 * @return the real height of a raster cell
-	 */
-	public final double getCellHeight() {
-		return getRealHeight() / getHeight();
-	}
-
-	public final String toString() {
-		return "MetaData: type:" + dataType + " wc:" + width + "hc:" + height
-				+ " minX:" + minX + " minY:" + minY + " x:" + x + " y:" + y
-				+ " rw:" + realWidth + " rh:" + realHeight;
-	}
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package appl.util;
+
+import java.awt.image.DataBuffer;
+import java.io.Serializable;
+
+import org.geotools.referencing.crs.DefaultGeographicCRS;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+
+import schmitzm.data.WritableGrid;
+
+/**
+ * Simple immutable class that encapsulates raster metadata, 
+ * especially the MetaData of a {@link WritableGrid}. 
+ * Just a constructor and getters
+ * on the fields.
+ * 
+ * <br> 
+ * @see WritableGrid for details on the variable description
+ *
+ * @author Dominik Appl
+ */
+public final class RasterMetaData implements Serializable {
+
+    int width = 0;
+
+    int height = 0;
+
+    int minX = 0;
+
+    int minY = 0;
+
+    double realWidth = 0;
+
+    double realHeight = 0;
+
+    int dataType = DataBuffer.TYPE_UNDEFINED;
+
+    double x = 0.0;
+
+    double y = 0.0;
+
+    CoordinateReferenceSystem crs = null;
+
+
+        /**
+         * @return Returns the CRS of the raster
+         */
+        public final CoordinateReferenceSystem getCoordinateReferenceSystem() {
+          return crs;
+        }
+
+	/**
+	 * @return Returns the height in cells
+	 */
+	public final int getHeight() {
+		return height;
+	}
+
+	/**
+	 * @return Returns the width in cells.
+	 */
+	public final int getWidth() {
+		return width;
+	}
+
+	/**
+	 * @return Returns the dataType.
+	 */
+	public final int getDataType() {
+		return dataType;
+	}
+
+	/**
+	 * @return Returns minX (used to indicate a start index)
+	 * @see WritableGrid#getMinX()
+	 */
+	public final int getMinX() {
+		return minX;
+	}
+
+	/**
+	 * @return Returns the minY ((used to indicate a start index)
+	 * @see WritableGrid#getMinY()
+	 */
+	public final int getMinY() {
+		return minY;
+	}
+
+	/**
+	 * @return Returns the realHeight.
+	 */
+	public final double getRealHeight() {
+		return realHeight;
+	}
+
+	/**
+	 * @return Returns the realWidth.
+	 */
+	public final double getRealWidth() {
+		return realWidth;
+	}
+
+	/**
+	 * @return Returns the (geographic) x-coordinate
+	 */
+	public final double getX() {
+		return x;
+	}
+
+
+	/**
+	 * @return Returns  the (geographic) y-coordinate
+	 */
+	public final double getY() {
+		return y;
+	}
+
+	/**
+	 * @param dataType the datatype
+	 * @param gridWidth the width of the grid (in cells)
+	 * @param gridHeight the height of the grid (in cells)
+	 * @param minX the minX (used to indicate a start index)
+	 * @param minY the minY (used to indicate a start index)
+	 * @param realWidth the real width
+	 * @param realHeight the real height
+	 * @param x the (geographic) x-coordinate
+	 * @param y the (geographic) y-coordinate
+     * @param crs the {@link CoordinateReferenceSystem}. Use null for DefaultCRS (WGS84)
+     * 
+     * @see WritableGrid
+	 */
+	public RasterMetaData(int dataType, int gridWidth, int gridHeight,
+			int minX, int minY, double x, double y, double realWidth,
+			double realHeight, CoordinateReferenceSystem crs) {
+		this.width = gridWidth;
+		this.height = gridHeight;
+		this.minX = minX;
+		this.minY = minY;
+		this.realWidth = realWidth;
+		this.realHeight = realHeight;
+		this.dataType = dataType;
+		this.x = x;
+		this.y = y;
+		this.crs = (crs == null) ? DefaultGeographicCRS.WGS84 : crs;
+        
+	}
+
+	/**
+	 * Constructs a RasterMetaData Object. The values of the real height/ width 
+	 * are calculated out of the cellsize. The cells are assumed to be squares.
+	 * 
+	 * @param dataType the datatype
+	 * @param gridWidth the width of the grid (in cells)
+	 * @param gridHeight the height of the grid (in cells)
+	 * @param minX the minX (used to indicate a start index)
+	 * @param minY the minY (used to indicate a start index)
+	 * @param x the (geographic) x-coordinate
+	 * @param y the (geographic) y-coordinate
+	 * @param cellSize the real size of one cell
+     * @param crs the {@link CoordinateReferenceSystem}, use null for default CRS (WGS84)
+	 */
+	public RasterMetaData(int dataType,  int gridWidth, int gridHeight,
+			int minX, int minY, double x, double y, double cellSize, CoordinateReferenceSystem crs) {
+
+		this(dataType, gridWidth, gridHeight, minX, minY, x, y, gridWidth
+				* cellSize, gridHeight * cellSize,crs);
+	}
+
+	/**
+	 * Constructs a RasterMetaDataObject out of the given Grid
+	 * @param w the source grid
+	 */
+	public RasterMetaData(WritableGrid w) {
+        super();
+        this.width = w.getWidth();
+        this.height = w.getHeight();
+        this.minX = w.getMinX();
+        this.minY = w.getMinY();
+        this.realWidth = w.getRealWidth();
+        this.realHeight = w.getRealHeight();
+        this.dataType = w.getSampleType();
+        this.x = w.getX();
+        this.y = w.getY();
+        this.crs = w.getCoordinateReferenceSystem();
+    }
+
+	/**
+	 * needed for serialization
+	 */
+	private RasterMetaData() {
+	 this(0,0,0,0,0,0,0,0,0,null);
+	}
+
+	/**
+	 * @return the real width of a raster cell
+	 */
+	public final double getCellWidth() {
+		return getRealWidth() / getWidth();
+	}
+
+	/**
+	 * Checks if the given RasterMetaData object has the same values.
+	 *
+	 * @param rasterMeta must be a RasterMetaDataObject! Else ClassCastException will be thrown.
+	 * @return true, if all values are the same
+	 * @see java.lang.Object#equals(java.lang.Object)
+	 */
+	@Override
+	public boolean equals(Object rasterMeta) {
+		RasterMetaData r = (RasterMetaData) rasterMeta;
+        return (
+        		this.width == r.getWidth() &&
+        		this.height == r.getHeight() &&
+        		this.minX == r.getMinX() &&
+        		this.minY == r.getMinY() &&
+        		this.realWidth == r.getRealWidth() &&
+        		this.realHeight == r.getRealHeight() &&
+        		this.dataType == r.getDataType() &&
+        		this.x == r.getX() &&
+        		this.y == r.getY()
+        		);
+	}
+
+	/**
+	 * @return the real height of a raster cell
+	 */
+	public final double getCellHeight() {
+		return getRealHeight() / getHeight();
+	}
+
+	public final String toString() {
+		return "MetaData: type:" + dataType + " wc:" + width + "hc:" + height
+				+ " minX:" + minX + " minY:" + minY + " x:" + x + " y:" + y
+				+ " rw:" + realWidth + " rh:" + realHeight;
+	}
+}

Modified: trunk/src/junit/skrueger/i8n/SwitchLanguageDialogTest.java
===================================================================
--- trunk/src/junit/skrueger/i8n/SwitchLanguageDialogTest.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/junit/skrueger/i8n/SwitchLanguageDialogTest.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,3 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package junit.skrueger.i8n;
 
 import java.util.ArrayList;

Modified: trunk/src/schmitzm/data/AbstractReadableGrid.java
===================================================================
--- trunk/src/schmitzm/data/AbstractReadableGrid.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/AbstractReadableGrid.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,375 +1,393 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.data;
-
-import org.geotools.referencing.crs.DefaultGeographicCRS;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-
-import schmitzm.geotools.grid.GridUtil;
-import appl.data.LoadingException;
-
-/**
- * Diese Klasse bildet eine Basis-Implementierung von {@link ReadableGrid}.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public abstract class AbstractReadableGrid implements ReadableGrid {
-  /** Enthaelt das CRS des Rasters */
-  protected CoordinateReferenceSystem crs = null;
-
-  /**
-   * Erzeugt ein AbstractReadableGrid.
-   * @param crs CoordinateReferenceSystem
-   */
-  public AbstractReadableGrid(CoordinateReferenceSystem crs) {
-    this.crs = (crs == null) ? DefaultGeographicCRS.WGS84 : crs;
-  }
-
-  /**
-   * Creates an abstract ReadableGrid with a default CRS (WGS84)
-   */
-  public AbstractReadableGrid() {
-    this(null);
-  }
-
-	/**
-	 * This class does not support late loading itself!
-	 *
-	 * @see appl.data.LateLoadable#unloadData()
-	 * @return false;
-	 * @see appl.data.LateLoadable#isLateLoadable()
-	 */
-	public boolean isLateLoadable() {
-		return false;
-	}
-
-	/**
-	 * Does nothing!
-	 *
-	 * This class  does not support late loading!
-	 *
-	 * @see appl.data.LateLoadable#unloadData()
-	 * @see appl.data.LateLoadable#loadData()
-	 */
-	public void loadData() throws LoadingException {
-	}
-
-	/**
-	 * Does nothing!
-	 *
-	 * This class does not support late loading!
-	 *
-	 * @see appl.data.LateLoadable#unloadData()
-	 */
-	public void unloadData(){
-	}
-
-  /**
-   * Liefert das CRS des Rasters.
-   */
-  public CoordinateReferenceSystem getCoordinateReferenceSystem() {
-    return this.crs;
-  }
-
-
-   /**
-   * Liefert die reale Breite einer Rasterzelle.
-   * @return <code>getRealWidth() / getWidth()</code>
-   */
-  public double getCellWidth() {
-    return getRealWidth() / getWidth();
-  }
-
-  /**
-   * Liefert die reale Breite einer Rasterzelle.
-   * @return <code>getRealHeight() / getHeight()</code>
-   */
-  public double getCellHeight() {
-    return getRealHeight() / getHeight();
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
-   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-   *             {@link #getMinX()} und {@link #getMinY()})
-   */
-  public short getRasterSampleAsShort(int... cell) {
-    return ((Number)getRasterSample(cell)).shortValue();
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
-   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-   *             {@link #getMinX()} und {@link #getMinY()})
-   */
-  public byte getRasterSampleAsByte(int... cell) {
-    return ((Number)getRasterSample(cell)).byteValue();
-  }
-
-
-  /**
-   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
-   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-   *             {@link #getMinX()} und {@link #getMinY()})
-   */
-  public int getRasterSampleAsInt(int... cell) {
-    return ((Number)getRasterSample(cell)).intValue();
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
-   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-   *             {@link #getMinX()} und {@link #getMinY()})
-   */
-  public long getRasterSampleAsLong(int... cell) {
-    return ((Number)getRasterSample(cell)).longValue();
-  }
-
-
-  /**
-   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
-   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-   *             {@link #getMinX()} und {@link #getMinY()})
-   */
-  public float getRasterSampleAsFloat(int... cell) {
-    return ((Number)getRasterSample(cell)).floatValue();
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
-   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-   *             {@link #getMinX()} und {@link #getMinY()})
-   */
-  public double getRasterSampleAsDouble(int... cell) {
-    return ((Number)getRasterSample(cell)).doubleValue();
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
-   * Liegt der Koordinatenwert genau auf der Grenze zwischen zwei Rasterzellen,
-   * wird die naechst groessere Zelle gewaehlt (ausser die Grenze entspricht
-   * dem Raster-Rand!).
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
-   *            Koordinaten angegeben werden
-   */
-  public Object getGridSample(double... coord) {
-    if ( coord.length < RASTER_DIM )
-      throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
-    // Koordinaten umrechnen in Zellen-Index
-    int cellX = convertRealToRaster(coord[0],0);
-    int cellY = convertRealToRaster(coord[1],1);
-    return getRasterSample(cellX,cellY);
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   */
-  public short getGridSampleAsShort(double... coord) {
-    return ((Number)getGridSample(coord)).shortValue();
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   */
-  public byte getGridSampleAsByte(double... coord){
-    return ((Number)getGridSample(coord)).byteValue();
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   */
-  public int getGridSampleAsInt(double... coord){
-    return ((Number)getGridSample(coord)).intValue();
-  }
-
-
-  /**
-   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   */
-  public long getGridSampleAsLong(double... coord){
-    return ((Number)getGridSample(coord)).longValue();
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   */
-  public float getGridSampleAsFloat(double... coord){
-    return ((Number)getGridSample(coord)).floatValue();
-  }
-
-
-  /**
-   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   */
-  public double getGridSampleAsDouble(double... coord){
-    return ((Number)getGridSample(coord)).doubleValue();
-  }
-
-  /**
-   * Konvertiert eine reale Koordinate in eine Zellennummer. Liegt der
-   * Koordinatenwert genau auf der Grenze zwischen zwei Rasterzellen, wird
-   * die naechst "groessere" Zellegewaehlt.
-   * Ausnahme bildet der Rand des Rasters. Hier wird die kleinere Zelle
-   * (also die letzte) herangezogen
-   * @param coord Georeferenz-Koordinate
-   * @param dim   Dimension, in der die Umrechnung erfolgen soll
-   * @exception UnsupportedOperationException falls eine ungueltige Dimension
-   *            angegeben wird (nur Werte 0 <= coord < {@link #RASTER_DIM} sind
-   *            zulaessig
-   */
-  public int convertRealToRaster(final double coord, final int dim) {
-    return convertRealToRaster(this,coord,dim);
-  }
-
-  /**
-   * Konvertiert eine Zellennummer in reale Koordinate. Dabei wird die
-   * Koordinate der Zellenmitte zurueckgegeben.
-   * @param cell  Rasterzellen-Koordinate
-   * @param dim   Dimension, in der die Umrechnung erfolgen soll
-   * @exception UnsupportedOperationException falls eine ungueltige Dimension
-   *            angegeben wird (nur Werte 0 <= coord < {@link #RASTER_DIM} sind
-   *            zulaessig
-   */
-  public double convertRasterToReal(final int cell, final int dim) {
-    return convertRasterToReal(this,cell,dim);
-  }
-
-  /**
-   * Konvertiert eine reale Koordinate in eine Zellennummer. Liegt der
-   * Koordinatenwert genau auf der Grenze zwischen zwei Rasterzellen, wird
-   * die naechst "groessere" Zellegewaehlt.
-   * Ausnahme bildet der Rand des Rasters. Hier wird die kleinere Zelle
-   * (also die letzte) herangezogen.
-   * @param grid  Raster fuer das die Umrechnung vorgenommen wird
-   * @param coord Georeferenz-Koordinate
-   * @param dim   Dimension, in der die Umrechnung erfolgen soll
-   * @exception UnsupportedOperationException falls eine ungueltige Dimension
-   *            angegeben wird (nur Werte 0 <= coord < {@link #RASTER_DIM} sind
-   *            zulaessig
-   */
-  public static int convertRealToRaster(ReadableGrid grid, double coord, int dim) {
-    if ( dim < 0 || dim >= RASTER_DIM )
-      throw new UnsupportedOperationException(RASTER_DIM+" is the maximum dimension!");
-
-    int    rasterMin    = (dim==0) ? grid.getMinX()      : grid.getMinY();
-    double realMin      = (dim==0) ? grid.getX()         : grid.getY();
-    int    rasterLength = (dim==0) ? grid.getWidth()     : grid.getHeight();
-    double realLength   = (dim==0) ? grid.getRealWidth() : grid.getRealHeight();
-    double cellSize     = (dim==0) ? grid.getCellWidth() : grid.getCellHeight();
-
-    int cell = convertRealToRaster(coord, realMin, realLength, rasterMin, rasterLength);
-    // In Y-Richtung liegt der Raster-Ursprung eines Grids OBEN, waehrend die
-    // Latitude-Referenz die UNTERE Grid-Kante beschreibt
-    // -> Umrechnen
-    if ( dim == 1 )
-      cell = rasterMin+rasterLength - cell - 1;
-    return cell;
-  }
-
-  /**
-   * Konvertiert eine Zellennummer in eine reale Koordinate. Dabei wird die
-   * Koordinate der Zellenmitte zurueckgegeben.
-   * @param grid  Raster fuer das die Umrechnung vorgenommen wird
-   * @param cell  Rasterzellen-Koordinate
-   * @param dim   Dimension, in der die Umrechnung erfolgen soll
-   * @exception UnsupportedOperationException falls eine ungueltige Dimension
-   *            angegeben wird (nur Werte 0 <= coord < {@link #RASTER_DIM} sind
-   *            zulaessig
-   */
-  public static double convertRasterToReal(ReadableGrid grid, int cell, int dim) {
-    if ( dim < 0 || dim >= RASTER_DIM )
-      throw new UnsupportedOperationException(RASTER_DIM+" is the maximum dimension!");
-
-    int    rasterMin    = (dim==0) ? grid.getMinX()      : grid.getMinY();
-    double realMin      = (dim==0) ? grid.getX()         : grid.getY();
-    int    rasterLength = (dim==0) ? grid.getWidth()     : grid.getHeight();
-    double realLength   = (dim==0) ? grid.getRealWidth() : grid.getRealHeight();
-    double cellSize     = (dim==0) ? grid.getCellWidth() : grid.getCellHeight();
-
-    // In Y-Richtung liegt der Raster-Ursprung eines Grids OBEN, waehrend die
-    // Longitude-Referenz die UNTERE Grid-Kante beschreibt
-    // -> Y-Koordinate umrechnen in "Sicht aus UNTERER Ecke"
-    if ( dim == 1 )
-      cell = rasterMin+rasterLength - cell - 1;
-
-    return convertRasterToReal(cell,rasterMin,realMin,cellSize);
-  }
-
-  /**
-   * Konvertiert eine reale Koordinate in eine Zellennummer.
-   * Siehe {@link GridUtil#convertRealToRaster(double, double, double, int, int)}.
-   * @param coord Georeferenz-Koordinate, die umgerechnet werden soll
-   * @param realMin    Minimale Welt-Koordinate (in der gewuenschten Richtung/Dimension) des
-   *                   Grids in dem sich die Zelle befindet
-   * @param realLength Reale Laenge (in der gewuenschten Richtung/Dimension) des
-   *                   Grids in dem sich die Zelle befindet
-   * @param rasterMin    Minimale Zellen-Nummer (in der gewuenschten Richtung/Dimension) des
-   *                     Grids in dem sich die Zelle befindet
-   * @param rasterLength Laenge in Zellen (in der gewuenschten Richtung/Dimension) des
-   *                     Grids in dem sich die Zelle befindet
-   */
-  public static int convertRealToRaster(final double coord, final double realMin, final double realLength, final int rasterMin, final int rasterLength) {
-    return GridUtil.convertRealToRaster(coord, realMin, realLength, rasterMin, rasterLength);
-  }
-
-  /**
-   * Konvertiert eine Zellennummer in eine reale Koordinate.
-   * Siehe {@link GridUtil#convertRasterToReal(int, int, double, double)}.
-   * @param cell       Rasterzellen-Koordinate, die umgerechnet werden soll
-   * @param rasterMin  Minimale Raster-Koordinate (in der gewuenschten Richtung/Dimension) des
-   *                   Grids in dem sich die Zelle befindet
-   * @param realMin    Minimale Welt-Koordinate (in der gewuenschten Richtung/Dimension) des
-   *                   Grids in dem sich die Zelle befindet
-   * @param cellSize   Zellengroesse (in der gewuenschten Richtung/Dimension) des
-   *                   Grids in dem sich die Zelle befindet
-   */
-  public static double convertRasterToReal(final int cell, final int rasterMin, final double realMin, final double cellSize) {
-    return GridUtil.convertRasterToReal(cell, rasterMin, realMin, cellSize);
-  }
-  
-  /**
-   * Vergleicht zwei Raster auf gleiche Struktur (Hoehe, Breite, Zell-Hoehe,
-   * Zell-Breite, Sample-Type).
-   * @param grid1 Raster 1
-   * @param desc1 Beschreibung von Raster 1 (fuer Fehlermeldung)
-   * @param grid2 Raster 2
-   * @param desc2 Beschreibung von Raster 2 (fuer Fehlermeldung)
-   * @param checkType bestimmt, ob auch der Sample-Type uebereinstimmen muss
-   * @exception UnsupportedOperationException falls die Raster nicht gleich sind
-   */
-  public static void compareStructure(ReadableGrid grid1, String desc1, ReadableGrid grid2, String desc2, boolean checkType) {
-    if ( grid1.getWidth() != grid2.getWidth() )
-      throw new UnsupportedOperationException(createCompareMessage(DataUtil.RESOURCE.getString("RasterDim.GridWidth"),desc1,desc2));
-    if ( grid1.getHeight() != grid2.getHeight() )
-      throw new UnsupportedOperationException(createCompareMessage(DataUtil.RESOURCE.getString("RasterDim.GridHeight"),desc1,desc2));
-    if ( grid1.getCellWidth() != grid2.getCellWidth() )
-      throw new UnsupportedOperationException(createCompareMessage(DataUtil.RESOURCE.getString("RasterDim.CellWidth"),desc1,desc2));
-    if ( grid1.getCellHeight() != grid2.getCellHeight() )
-      throw new UnsupportedOperationException(createCompareMessage(DataUtil.RESOURCE.getString("RasterDim.CellHeight"),desc1,desc2));
-    if ( checkType && grid1.getSampleType() != grid2.getSampleType() )
-      throw new UnsupportedOperationException(createCompareMessage(DataUtil.RESOURCE.getString("RasterDim.SampleType"),desc1,desc2));
-  }
-
-  /**
-   * Erzeugt eine Fehlermeldung fuer eine bestimmte inkompatible Raster-Struktur.
-   */
-  private static String createCompareMessage(String compType, String objDesc1, String objDesc2) {
-    return DataUtil.RESOURCE.getString("RasterDim.ErrorMess",compType,objDesc1,objDesc2);
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data;
+
+import org.geotools.referencing.crs.DefaultGeographicCRS;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+
+import schmitzm.geotools.grid.GridUtil;
+import appl.data.LoadingException;
+
+/**
+ * Diese Klasse bildet eine Basis-Implementierung von {@link ReadableGrid}.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public abstract class AbstractReadableGrid implements ReadableGrid {
+  /** Enthaelt das CRS des Rasters */
+  protected CoordinateReferenceSystem crs = null;
+
+  /**
+   * Erzeugt ein AbstractReadableGrid.
+   * @param crs CoordinateReferenceSystem
+   */
+  public AbstractReadableGrid(CoordinateReferenceSystem crs) {
+    this.crs = (crs == null) ? DefaultGeographicCRS.WGS84 : crs;
+  }
+
+  /**
+   * Creates an abstract ReadableGrid with a default CRS (WGS84)
+   */
+  public AbstractReadableGrid() {
+    this(null);
+  }
+
+	/**
+	 * This class does not support late loading itself!
+	 *
+	 * @see appl.data.LateLoadable#unloadData()
+	 * @return false;
+	 * @see appl.data.LateLoadable#isLateLoadable()
+	 */
+	public boolean isLateLoadable() {
+		return false;
+	}
+
+	/**
+	 * Does nothing!
+	 *
+	 * This class  does not support late loading!
+	 *
+	 * @see appl.data.LateLoadable#unloadData()
+	 * @see appl.data.LateLoadable#loadData()
+	 */
+	public void loadData() throws LoadingException {
+	}
+
+	/**
+	 * Does nothing!
+	 *
+	 * This class does not support late loading!
+	 *
+	 * @see appl.data.LateLoadable#unloadData()
+	 */
+	public void unloadData(){
+	}
+
+  /**
+   * Liefert das CRS des Rasters.
+   */
+  public CoordinateReferenceSystem getCoordinateReferenceSystem() {
+    return this.crs;
+  }
+
+
+   /**
+   * Liefert die reale Breite einer Rasterzelle.
+   * @return <code>getRealWidth() / getWidth()</code>
+   */
+  public double getCellWidth() {
+    return getRealWidth() / getWidth();
+  }
+
+  /**
+   * Liefert die reale Breite einer Rasterzelle.
+   * @return <code>getRealHeight() / getHeight()</code>
+   */
+  public double getCellHeight() {
+    return getRealHeight() / getHeight();
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
+   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+   *             {@link #getMinX()} und {@link #getMinY()})
+   */
+  public short getRasterSampleAsShort(int... cell) {
+    return ((Number)getRasterSample(cell)).shortValue();
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
+   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+   *             {@link #getMinX()} und {@link #getMinY()})
+   */
+  public byte getRasterSampleAsByte(int... cell) {
+    return ((Number)getRasterSample(cell)).byteValue();
+  }
+
+
+  /**
+   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
+   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+   *             {@link #getMinX()} und {@link #getMinY()})
+   */
+  public int getRasterSampleAsInt(int... cell) {
+    return ((Number)getRasterSample(cell)).intValue();
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
+   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+   *             {@link #getMinX()} und {@link #getMinY()})
+   */
+  public long getRasterSampleAsLong(int... cell) {
+    return ((Number)getRasterSample(cell)).longValue();
+  }
+
+
+  /**
+   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
+   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+   *             {@link #getMinX()} und {@link #getMinY()})
+   */
+  public float getRasterSampleAsFloat(int... cell) {
+    return ((Number)getRasterSample(cell)).floatValue();
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
+   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+   *             {@link #getMinX()} und {@link #getMinY()})
+   */
+  public double getRasterSampleAsDouble(int... cell) {
+    return ((Number)getRasterSample(cell)).doubleValue();
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
+   * Liegt der Koordinatenwert genau auf der Grenze zwischen zwei Rasterzellen,
+   * wird die naechst groessere Zelle gewaehlt (ausser die Grenze entspricht
+   * dem Raster-Rand!).
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
+   *            Koordinaten angegeben werden
+   */
+  public Object getGridSample(double... coord) {
+    if ( coord.length < RASTER_DIM )
+      throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
+    // Koordinaten umrechnen in Zellen-Index
+    int cellX = convertRealToRaster(coord[0],0);
+    int cellY = convertRealToRaster(coord[1],1);
+    return getRasterSample(cellX,cellY);
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   */
+  public short getGridSampleAsShort(double... coord) {
+    return ((Number)getGridSample(coord)).shortValue();
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   */
+  public byte getGridSampleAsByte(double... coord){
+    return ((Number)getGridSample(coord)).byteValue();
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   */
+  public int getGridSampleAsInt(double... coord){
+    return ((Number)getGridSample(coord)).intValue();
+  }
+
+
+  /**
+   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   */
+  public long getGridSampleAsLong(double... coord){
+    return ((Number)getGridSample(coord)).longValue();
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   */
+  public float getGridSampleAsFloat(double... coord){
+    return ((Number)getGridSample(coord)).floatValue();
+  }
+
+
+  /**
+   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   */
+  public double getGridSampleAsDouble(double... coord){
+    return ((Number)getGridSample(coord)).doubleValue();
+  }
+
+  /**
+   * Konvertiert eine reale Koordinate in eine Zellennummer. Liegt der
+   * Koordinatenwert genau auf der Grenze zwischen zwei Rasterzellen, wird
+   * die naechst "groessere" Zellegewaehlt.
+   * Ausnahme bildet der Rand des Rasters. Hier wird die kleinere Zelle
+   * (also die letzte) herangezogen
+   * @param coord Georeferenz-Koordinate
+   * @param dim   Dimension, in der die Umrechnung erfolgen soll
+   * @exception UnsupportedOperationException falls eine ungueltige Dimension
+   *            angegeben wird (nur Werte 0 <= coord < {@link #RASTER_DIM} sind
+   *            zulaessig
+   */
+  public int convertRealToRaster(final double coord, final int dim) {
+    return convertRealToRaster(this,coord,dim);
+  }
+
+  /**
+   * Konvertiert eine Zellennummer in reale Koordinate. Dabei wird die
+   * Koordinate der Zellenmitte zurueckgegeben.
+   * @param cell  Rasterzellen-Koordinate
+   * @param dim   Dimension, in der die Umrechnung erfolgen soll
+   * @exception UnsupportedOperationException falls eine ungueltige Dimension
+   *            angegeben wird (nur Werte 0 <= coord < {@link #RASTER_DIM} sind
+   *            zulaessig
+   */
+  public double convertRasterToReal(final int cell, final int dim) {
+    return convertRasterToReal(this,cell,dim);
+  }
+
+  /**
+   * Konvertiert eine reale Koordinate in eine Zellennummer. Liegt der
+   * Koordinatenwert genau auf der Grenze zwischen zwei Rasterzellen, wird
+   * die naechst "groessere" Zellegewaehlt.
+   * Ausnahme bildet der Rand des Rasters. Hier wird die kleinere Zelle
+   * (also die letzte) herangezogen.
+   * @param grid  Raster fuer das die Umrechnung vorgenommen wird
+   * @param coord Georeferenz-Koordinate
+   * @param dim   Dimension, in der die Umrechnung erfolgen soll
+   * @exception UnsupportedOperationException falls eine ungueltige Dimension
+   *            angegeben wird (nur Werte 0 <= coord < {@link #RASTER_DIM} sind
+   *            zulaessig
+   */
+  public static int convertRealToRaster(ReadableGrid grid, double coord, int dim) {
+    if ( dim < 0 || dim >= RASTER_DIM )
+      throw new UnsupportedOperationException(RASTER_DIM+" is the maximum dimension!");
+
+    int    rasterMin    = (dim==0) ? grid.getMinX()      : grid.getMinY();
+    double realMin      = (dim==0) ? grid.getX()         : grid.getY();
+    int    rasterLength = (dim==0) ? grid.getWidth()     : grid.getHeight();
+    double realLength   = (dim==0) ? grid.getRealWidth() : grid.getRealHeight();
+    double cellSize     = (dim==0) ? grid.getCellWidth() : grid.getCellHeight();
+
+    int cell = convertRealToRaster(coord, realMin, realLength, rasterMin, rasterLength);
+    // In Y-Richtung liegt der Raster-Ursprung eines Grids OBEN, waehrend die
+    // Latitude-Referenz die UNTERE Grid-Kante beschreibt
+    // -> Umrechnen
+    if ( dim == 1 )
+      cell = rasterMin+rasterLength - cell - 1;
+    return cell;
+  }
+
+  /**
+   * Konvertiert eine Zellennummer in eine reale Koordinate. Dabei wird die
+   * Koordinate der Zellenmitte zurueckgegeben.
+   * @param grid  Raster fuer das die Umrechnung vorgenommen wird
+   * @param cell  Rasterzellen-Koordinate
+   * @param dim   Dimension, in der die Umrechnung erfolgen soll
+   * @exception UnsupportedOperationException falls eine ungueltige Dimension
+   *            angegeben wird (nur Werte 0 <= coord < {@link #RASTER_DIM} sind
+   *            zulaessig
+   */
+  public static double convertRasterToReal(ReadableGrid grid, int cell, int dim) {
+    if ( dim < 0 || dim >= RASTER_DIM )
+      throw new UnsupportedOperationException(RASTER_DIM+" is the maximum dimension!");
+
+    int    rasterMin    = (dim==0) ? grid.getMinX()      : grid.getMinY();
+    double realMin      = (dim==0) ? grid.getX()         : grid.getY();
+    int    rasterLength = (dim==0) ? grid.getWidth()     : grid.getHeight();
+    double realLength   = (dim==0) ? grid.getRealWidth() : grid.getRealHeight();
+    double cellSize     = (dim==0) ? grid.getCellWidth() : grid.getCellHeight();
+
+    // In Y-Richtung liegt der Raster-Ursprung eines Grids OBEN, waehrend die
+    // Longitude-Referenz die UNTERE Grid-Kante beschreibt
+    // -> Y-Koordinate umrechnen in "Sicht aus UNTERER Ecke"
+    if ( dim == 1 )
+      cell = rasterMin+rasterLength - cell - 1;
+
+    return convertRasterToReal(cell,rasterMin,realMin,cellSize);
+  }
+
+  /**
+   * Konvertiert eine reale Koordinate in eine Zellennummer.
+   * Siehe {@link GridUtil#convertRealToRaster(double, double, double, int, int)}.
+   * @param coord Georeferenz-Koordinate, die umgerechnet werden soll
+   * @param realMin    Minimale Welt-Koordinate (in der gewuenschten Richtung/Dimension) des
+   *                   Grids in dem sich die Zelle befindet
+   * @param realLength Reale Laenge (in der gewuenschten Richtung/Dimension) des
+   *                   Grids in dem sich die Zelle befindet
+   * @param rasterMin    Minimale Zellen-Nummer (in der gewuenschten Richtung/Dimension) des
+   *                     Grids in dem sich die Zelle befindet
+   * @param rasterLength Laenge in Zellen (in der gewuenschten Richtung/Dimension) des
+   *                     Grids in dem sich die Zelle befindet
+   */
+  public static int convertRealToRaster(final double coord, final double realMin, final double realLength, final int rasterMin, final int rasterLength) {
+    return GridUtil.convertRealToRaster(coord, realMin, realLength, rasterMin, rasterLength);
+  }
+
+  /**
+   * Konvertiert eine Zellennummer in eine reale Koordinate.
+   * Siehe {@link GridUtil#convertRasterToReal(int, int, double, double)}.
+   * @param cell       Rasterzellen-Koordinate, die umgerechnet werden soll
+   * @param rasterMin  Minimale Raster-Koordinate (in der gewuenschten Richtung/Dimension) des
+   *                   Grids in dem sich die Zelle befindet
+   * @param realMin    Minimale Welt-Koordinate (in der gewuenschten Richtung/Dimension) des
+   *                   Grids in dem sich die Zelle befindet
+   * @param cellSize   Zellengroesse (in der gewuenschten Richtung/Dimension) des
+   *                   Grids in dem sich die Zelle befindet
+   */
+  public static double convertRasterToReal(final int cell, final int rasterMin, final double realMin, final double cellSize) {
+    return GridUtil.convertRasterToReal(cell, rasterMin, realMin, cellSize);
+  }
+  
+  /**
+   * Vergleicht zwei Raster auf gleiche Struktur (Hoehe, Breite, Zell-Hoehe,
+   * Zell-Breite, Sample-Type).
+   * @param grid1 Raster 1
+   * @param desc1 Beschreibung von Raster 1 (fuer Fehlermeldung)
+   * @param grid2 Raster 2
+   * @param desc2 Beschreibung von Raster 2 (fuer Fehlermeldung)
+   * @param checkType bestimmt, ob auch der Sample-Type uebereinstimmen muss
+   * @exception UnsupportedOperationException falls die Raster nicht gleich sind
+   */
+  public static void compareStructure(ReadableGrid grid1, String desc1, ReadableGrid grid2, String desc2, boolean checkType) {
+    if ( grid1.getWidth() != grid2.getWidth() )
+      throw new UnsupportedOperationException(createCompareMessage(DataUtil.RESOURCE.getString("RasterDim.GridWidth"),desc1,desc2));
+    if ( grid1.getHeight() != grid2.getHeight() )
+      throw new UnsupportedOperationException(createCompareMessage(DataUtil.RESOURCE.getString("RasterDim.GridHeight"),desc1,desc2));
+    if ( grid1.getCellWidth() != grid2.getCellWidth() )
+      throw new UnsupportedOperationException(createCompareMessage(DataUtil.RESOURCE.getString("RasterDim.CellWidth"),desc1,desc2));
+    if ( grid1.getCellHeight() != grid2.getCellHeight() )
+      throw new UnsupportedOperationException(createCompareMessage(DataUtil.RESOURCE.getString("RasterDim.CellHeight"),desc1,desc2));
+    if ( checkType && grid1.getSampleType() != grid2.getSampleType() )
+      throw new UnsupportedOperationException(createCompareMessage(DataUtil.RESOURCE.getString("RasterDim.SampleType"),desc1,desc2));
+  }
+
+  /**
+   * Erzeugt eine Fehlermeldung fuer eine bestimmte inkompatible Raster-Struktur.
+   */
+  private static String createCompareMessage(String compType, String objDesc1, String objDesc2) {
+    return DataUtil.RESOURCE.getString("RasterDim.ErrorMess",compType,objDesc1,objDesc2);
+  }
+}

Modified: trunk/src/schmitzm/data/AbstractWritableGrid.java
===================================================================
--- trunk/src/schmitzm/data/AbstractWritableGrid.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/AbstractWritableGrid.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,53 +1,71 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.data;
-
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-
-/**
- * Diese Klasse bildet eine Basis-Implementierung von {@link WritableGrid}.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public abstract class AbstractWritableGrid extends AbstractReadableGrid implements WritableGrid {
-  /**
-   * Erzeugt ein AbstractWritableGrid.
-   * @param crs CoordinateReferenceSystem
-   */
-  public AbstractWritableGrid(CoordinateReferenceSystem crs) {
-    super(crs);
-  }
-
-  /**
-   * Creates an abstract WritableGrid with a default CRS (WGS84)
-   */
-  public AbstractWritableGrid() {
-    this(null);
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Geo-Koordinaten. Liegt der
-   * Koordinatenwert genau auf der Grenze zwischen zwei Rasterzellen, wird die
-   * naechst groessere Zelle gewaehlt (ausser die Grenze entspricht dem Raster-Rand!).
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
-   *            Koordinaten angegeben werden
-   */
-  public void setGridSample(Object value, double... coord) {
-    if ( coord.length < RASTER_DIM )
-      throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
-    // Koordinaten umrechnen in Zellen-Index
-    int cellX = convertRealToRaster(coord[0],0);
-    int cellY = convertRealToRaster(coord[1],1);
-    setRasterSample(value,cellX,cellY);
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data;
+
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+
+/**
+ * Diese Klasse bildet eine Basis-Implementierung von {@link WritableGrid}.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public abstract class AbstractWritableGrid extends AbstractReadableGrid implements WritableGrid {
+  /**
+   * Erzeugt ein AbstractWritableGrid.
+   * @param crs CoordinateReferenceSystem
+   */
+  public AbstractWritableGrid(CoordinateReferenceSystem crs) {
+    super(crs);
+  }
+
+  /**
+   * Creates an abstract WritableGrid with a default CRS (WGS84)
+   */
+  public AbstractWritableGrid() {
+    this(null);
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Geo-Koordinaten. Liegt der
+   * Koordinatenwert genau auf der Grenze zwischen zwei Rasterzellen, wird die
+   * naechst groessere Zelle gewaehlt (ausser die Grenze entspricht dem Raster-Rand!).
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
+   *            Koordinaten angegeben werden
+   */
+  public void setGridSample(Object value, double... coord) {
+    if ( coord.length < RASTER_DIM )
+      throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
+    // Koordinaten umrechnen in Zellen-Index
+    int cellX = convertRealToRaster(coord[0],0);
+    int cellY = convertRealToRaster(coord[1],1);
+    setRasterSample(value,cellX,cellY);
+  }
+}

Modified: trunk/src/schmitzm/data/DataUtil.java
===================================================================
--- trunk/src/schmitzm/data/DataUtil.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/DataUtil.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,20 +1,49 @@
-package schmitzm.data;
-
-import java.util.Locale;
-
-import schmitzm.lang.LangUtil;
-import schmitzm.lang.ResourceProvider;
-
-/**
- * Diese Klasse enthaelt statische Hilfs-Methoden fuer das Package
- * {@code schmitzm.data}.
- * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class DataUtil {
-  /** {@link ResourceProvider}, der die Lokalisation fuer Komponenten
-   *  des Package {@code schmitzm.data} zur Verfuegung stellt. Diese sind
-   *  in properties-Datein unter {@code schmitzm.data.resource.locales}
-   *  hinterlegt. */
-  public static ResourceProvider RESOURCE = new ResourceProvider( LangUtil.extendPackagePath(DataUtil.class,"resource.locales.DataResourceBundle"), Locale.ENGLISH );
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data;
+
+import java.util.Locale;
+
+import schmitzm.lang.LangUtil;
+import schmitzm.lang.ResourceProvider;
+
+/**
+ * Diese Klasse enthaelt statische Hilfs-Methoden fuer das Package
+ * {@code schmitzm.data}.
+ * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class DataUtil {
+  /** {@link ResourceProvider}, der die Lokalisation fuer Komponenten
+   *  des Package {@code schmitzm.data} zur Verfuegung stellt. Diese sind
+   *  in properties-Datein unter {@code schmitzm.data.resource.locales}
+   *  hinterlegt. */
+  public static ResourceProvider RESOURCE = new ResourceProvider( LangUtil.extendPackagePath(DataUtil.class,"resource.locales.DataResourceBundle"), Locale.ENGLISH );
+}

Modified: trunk/src/schmitzm/data/ObjectStructure.java
===================================================================
--- trunk/src/schmitzm/data/ObjectStructure.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/ObjectStructure.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,16 +1,34 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.data;
-
 import java.util.Enumeration;
 
 import schmitzm.data.property.ListProperty;
@@ -18,59 +36,59 @@
 import schmitzm.data.property.Property;
 import schmitzm.data.property.PropertySet;
 import schmitzm.data.property.ScalarProperty;
-
-/**
- * Diese Klasse stellt die Struktur (nicht den Inhalt) eines "komplexen" Objekts
- * (Datentyps) dar. Ein "komplexes" Objekt kann z.B. eine {@linkplain ListProperty Liste}
- * sein, oder eine {@linkplain Properties Menge von Eigenschaften}.
- * Auch eine {@linkplain ScalarProperty skalare Eigenschaft} kann
- * bereits als komplexes Objekt aufgefasst werden, da sie einen Namen und ein
- * Unterobjekt enthaelt (welches wiederum komplex sein kann!).
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public interface ObjectStructure {
-  /**
-   * Liefert die Anzahl an Attributen, die der Datentyp hat. Bei einem
-   * {@link Properties}-Objekt entspricht dies z.B. der Anzahl an Propertys.
-   * Bei einer {@linkplain ListProperty Liste} von einfachen Elementen ist
-   * die Anzahl 1.
-   */
-  public int getAttrCount();
-
-  /**
-   * Liefert die Typen aller Attribute des Objekttyps. Dies kann wiederum
-   * eine <code>ObjectStructure</code> sein, oder eine <code>Class</code>-Instanz,
-   * falls das Attribut nicht weiter strukturiert werden kann.
-   * @return Aufzaehlung, in der jedes Element vom Typ <code>Class</code> oder
-   *         <code>ObjectStructure</code> ist
-   */
-  public Enumeration getAttrTypes();
-
-  /**
-   * Prueft, ob der Objekttyp einen Namen besitzt. z.B. ist eine {@link Property}
-   * i.d.R. benannt, ein {@link PropertySet} jedoch nicht.
-   */
-  public boolean isStructureNamed();
-
-  /**
-   * Liefert den Namen der <code>ObjectStructure</code>, falls sie benannt ist.
-   * @return <code>null</code> falls die Struktur unbenannt ist
-   * @see #isStructureNamed()
-   */
-  public String getStructureName();
-
-  /**
-   * Prueft, ob die Objektstruktur mehrere Instanzen aufnehmen kann. Dies ist
-   * z.B. fuer {@linkplain ListProperty Listen} der Fall, nicht jedoch fuer
-   * ein {@link PropertySet}, da dieses zwar verschiedene Attributwerte aufnimmt,
-   * fuer jedes Attribut jedoch immer nur eine Auspraegung!
-   */
-  public boolean containsMultipleValues();
-
-  /**
-   * Prueft, ob die Objekt-Struktur mit einer anderen identisch ist.
-   * @param object andere <code>ObjectStructure</code>
-   */
-  public boolean equalsInStructure(Object object);
-}
+
+/**
+ * Diese Klasse stellt die Struktur (nicht den Inhalt) eines "komplexen" Objekts
+ * (Datentyps) dar. Ein "komplexes" Objekt kann z.B. eine {@linkplain ListProperty Liste}
+ * sein, oder eine {@linkplain Properties Menge von Eigenschaften}.
+ * Auch eine {@linkplain ScalarProperty skalare Eigenschaft} kann
+ * bereits als komplexes Objekt aufgefasst werden, da sie einen Namen und ein
+ * Unterobjekt enthaelt (welches wiederum komplex sein kann!).
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public interface ObjectStructure {
+  /**
+   * Liefert die Anzahl an Attributen, die der Datentyp hat. Bei einem
+   * {@link Properties}-Objekt entspricht dies z.B. der Anzahl an Propertys.
+   * Bei einer {@linkplain ListProperty Liste} von einfachen Elementen ist
+   * die Anzahl 1.
+   */
+  public int getAttrCount();
+
+  /**
+   * Liefert die Typen aller Attribute des Objekttyps. Dies kann wiederum
+   * eine <code>ObjectStructure</code> sein, oder eine <code>Class</code>-Instanz,
+   * falls das Attribut nicht weiter strukturiert werden kann.
+   * @return Aufzaehlung, in der jedes Element vom Typ <code>Class</code> oder
+   *         <code>ObjectStructure</code> ist
+   */
+  public Enumeration getAttrTypes();
+
+  /**
+   * Prueft, ob der Objekttyp einen Namen besitzt. z.B. ist eine {@link Property}
+   * i.d.R. benannt, ein {@link PropertySet} jedoch nicht.
+   */
+  public boolean isStructureNamed();
+
+  /**
+   * Liefert den Namen der <code>ObjectStructure</code>, falls sie benannt ist.
+   * @return <code>null</code> falls die Struktur unbenannt ist
+   * @see #isStructureNamed()
+   */
+  public String getStructureName();
+
+  /**
+   * Prueft, ob die Objektstruktur mehrere Instanzen aufnehmen kann. Dies ist
+   * z.B. fuer {@linkplain ListProperty Listen} der Fall, nicht jedoch fuer
+   * ein {@link PropertySet}, da dieses zwar verschiedene Attributwerte aufnimmt,
+   * fuer jedes Attribut jedoch immer nur eine Auspraegung!
+   */
+  public boolean containsMultipleValues();
+
+  /**
+   * Prueft, ob die Objekt-Struktur mit einer anderen identisch ist.
+   * @param object andere <code>ObjectStructure</code>
+   */
+  public boolean equalsInStructure(Object object);
+}

Modified: trunk/src/schmitzm/data/ObjectStructureUtil.java
===================================================================
--- trunk/src/schmitzm/data/ObjectStructureUtil.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/ObjectStructureUtil.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,128 +1,146 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+import java.util.Enumeration;
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+/**
+ * Diese Klasse stellt statische Methoden fuer die Arbeit mit
+ * {@linkplain ObjectStructure Objekt-Strukturen} zur Verfuegung.
+ * Hierzu gehoeren insbesondere Vergleichsmethoden, mit denen auf strukturelle
+ * Gleichkeit oder Implikation getestet werden kann.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class ObjectStructureUtil {
+  /** Rueckgabe-Konstante fuer "zwei Strukturen sind identisch". */
+  public static final int EQUAL = 1;
+  /** Rueckgabe-Konstante fuer "die linke Strukturen umfasst die rechte". */
+  public static final int LEFT_CONTAINS_RIGHT = 2;
+  /** Rueckgabe-Konstante fuer "die rechte Strukturen umfasst die linke". */
+  public static final int RIGHT_CONTAINS_LEFT = 3;
+  /** Rueckgabe-Konstante fuer "weder umfasst die linke Strukur die rechte,
+   *  noch umgekehrt" (Ueberschneidung ist dennoch moeglich!). */
+  public static final int UNEQUAL = 4;
+  /** Rueckgabe-Konstante fuer "die beiden Strukituren haben eine leere Schnittmenge".<br>
+   *  <b>Bemerke</b>: wird z.Z. noch nicht verwendet!! */
+  public static final int DISJOINT = 5;
 
-package schmitzm.data;
-
-import java.util.Enumeration;
-
-/**
- * Diese Klasse stellt statische Methoden fuer die Arbeit mit
- * {@linkplain ObjectStructure Objekt-Strukturen} zur Verfuegung.
- * Hierzu gehoeren insbesondere Vergleichsmethoden, mit denen auf strukturelle
- * Gleichkeit oder Implikation getestet werden kann.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class ObjectStructureUtil {
-  /** Rueckgabe-Konstante fuer "zwei Strukturen sind identisch". */
-  public static final int EQUAL = 1;
-  /** Rueckgabe-Konstante fuer "die linke Strukturen umfasst die rechte". */
-  public static final int LEFT_CONTAINS_RIGHT = 2;
-  /** Rueckgabe-Konstante fuer "die rechte Strukturen umfasst die linke". */
-  public static final int RIGHT_CONTAINS_LEFT = 3;
-  /** Rueckgabe-Konstante fuer "weder umfasst die linke Strukur die rechte,
-   *  noch umgekehrt" (Ueberschneidung ist dennoch moeglich!). */
-  public static final int UNEQUAL = 4;
-  /** Rueckgabe-Konstante fuer "die beiden Strukituren haben eine leere Schnittmenge".<br>
-   *  <b>Bemerke</b>: wird z.Z. noch nicht verwendet!! */
-  public static final int DISJOINT = 5;
-
-  /**
-   * Vergleicht zwei Objekt-Strukturen.
-   * @param o1 "linke" Objekt-Struktur
-   * @param o2 "rechte" Objekt-Struktur
-   * @return eine der Konstanten {@link #EQUAL}, {@link #LEFT_CONTAINS_RIGHT},
-   *         {@link #RIGHT_CONTAINS_LEFT}, {@link #UNEQUAL}
-   * @see #checkStructureContainsStructure(ObjectStructure,ObjectStructure)
-   */
-  public static int compareObjectStructures(ObjectStructure o1, ObjectStructure o2) {
-    boolean o1_cont_o2 = checkStructureContainsStructure(o1,o2);
-    boolean o2_cont_o1 = checkStructureContainsStructure(o2,o1);
-    if ( o1_cont_o2 && o2_cont_o1 ) return EQUAL;
-    if ( o1_cont_o2  ) return LEFT_CONTAINS_RIGHT;
-    if ( o2_cont_o1  ) return RIGHT_CONTAINS_LEFT;
-    // Teil-Ueberschneidung wird (noch) nicht geprueft
-    return UNEQUAL;
-  }
-
-  /**
-   * Prueft, ob eine Objekt-Struktur eine andere umfasst.<br>
-   * <u>Vorgehensweise</u>:<br>
-   * <ol>
-   * <li>Kann die eine Struktur mehrere Werte aufnehmen und die andere nicht
-   *     ({@link ObjectStructure#containsMultipleValues()}), kann die linke
-   *     Struktur die rechte auf keinen Fall enthalten.</li>
-   * <li>Enhaelt die rechte Struktur mehr Attribute, als die linke, so kann die
-   *     linke Struktur die rechte auf keinen Fall enthalten.</li>
-   * <li>Enthaelt die linke Struktur ein Attribut, welches (wiederum strukturell)
-   *     nicht in der rechten Struktur vorhanden ist, so kann die linke Struktur
-   *     die rechte nicht enthalten.<br>
-   *     Beim Vergleich der Attribute wird wiederum auf strukturelle Implikation
-   *     geprueft:
-   *     <ul>
-   *     <li>Handelt es sich um zwei strukturierte Attribute, muss das "linke"
-   *         Attribut das "rechte" strukturell umfassen (Rekursion!).</li>
-   *     <li>Handelt es sich um zwei statische Attribute (Typ <code>Class</code>),
-   *         muss die "linke" Klasse eine Spezialisierung (Ableitung) der
-   *         "rechten" Klasse sein.</li>
-   *     <li>Treffen beide Bedingungen nicht zu, kann das linke Attribut das
-   *         rechte nicht umfassen.<li>
-   *     </ul></li>
-   * </ol>
-   * @param o1 "linke" Objekt-Struktur
-   * @param o2 "rechte" Objekt-Struktur
-   */
-  public static boolean checkStructureContainsStructure(ObjectStructure o1, ObjectStructure o2) {
-    if ( o1.containsMultipleValues() != o2.containsMultipleValues() ||
-         o2.getAttrCount() > o1.getAttrCount() )
-      return false;
-
-    // Pruefen, ob fuer jedes Attribut in o2 ein Attribut in o1 vorhanden ist,
-    //  welches o2 beinhaltet
-    for (Enumeration attr2 = o2.getAttrTypes(); attr2.hasMoreElements();)
-      if ( !findAttrTypeInStrcucture(attr2.nextElement(),o1) )
-        return false;
-
-    return true;
-  }
-
-  /**
-   * Prueft, ob ein Attribut in einer Objekt-Struktur (strukturell) enthalten ist.
-   * Erlaeuterungen ueber die Vorgehensweise sind in der Dokumenation zu
-   * {@link #checkStructureContainsStructure(ObjectStructure,ObjectStructure)}
-   * zu finden.
-   * @param type1 Attribut (<code>ObjectStructure</code>- oder
-   *              <code>Class</code>-Instanz)
-   * @param o2    Objekt-Struktur
-   */
-  private static boolean findAttrTypeInStrcucture(Object type1, ObjectStructure o2) {
-    for (Enumeration attr2 = o2.getAttrTypes(); attr2.hasMoreElements();) {
-      Object type2 = attr2.hasMoreElements();
-
-      // wenn es sich bei beiden um Strukturen handelt und Typ2 den gesuchten
-      // Typ1 impliziert, wurde Typ1 in der Struktur o2 gefunden
-      if (type1 instanceof ObjectStructure &&
-          type2 instanceof ObjectStructure &&
-          checkStructureContainsStructure((ObjectStructure)type2,(ObjectStructure)type1) )
-        return true;
-
-      // wenn es sich bei beiden um einfache Klassen handelt und Typ2 den gesuchten
-      // Typ1 impliziert, wurde Typ1 in der Struktur o2 gefunden
-      else if (type1 instanceof Class &&
-               type2 instanceof Class &&
-               ((Class)type2).isAssignableFrom((Class)type1) )
-             return true;
-    }
-
-    return false;
-  }
-
-}
+  /**
+   * Vergleicht zwei Objekt-Strukturen.
+   * @param o1 "linke" Objekt-Struktur
+   * @param o2 "rechte" Objekt-Struktur
+   * @return eine der Konstanten {@link #EQUAL}, {@link #LEFT_CONTAINS_RIGHT},
+   *         {@link #RIGHT_CONTAINS_LEFT}, {@link #UNEQUAL}
+   * @see #checkStructureContainsStructure(ObjectStructure,ObjectStructure)
+   */
+  public static int compareObjectStructures(ObjectStructure o1, ObjectStructure o2) {
+    boolean o1_cont_o2 = checkStructureContainsStructure(o1,o2);
+    boolean o2_cont_o1 = checkStructureContainsStructure(o2,o1);
+    if ( o1_cont_o2 && o2_cont_o1 ) return EQUAL;
+    if ( o1_cont_o2  ) return LEFT_CONTAINS_RIGHT;
+    if ( o2_cont_o1  ) return RIGHT_CONTAINS_LEFT;
+    // Teil-Ueberschneidung wird (noch) nicht geprueft
+    return UNEQUAL;
+  }
+
+  /**
+   * Prueft, ob eine Objekt-Struktur eine andere umfasst.<br>
+   * <u>Vorgehensweise</u>:<br>
+   * <ol>
+   * <li>Kann die eine Struktur mehrere Werte aufnehmen und die andere nicht
+   *     ({@link ObjectStructure#containsMultipleValues()}), kann die linke
+   *     Struktur die rechte auf keinen Fall enthalten.</li>
+   * <li>Enhaelt die rechte Struktur mehr Attribute, als die linke, so kann die
+   *     linke Struktur die rechte auf keinen Fall enthalten.</li>
+   * <li>Enthaelt die linke Struktur ein Attribut, welches (wiederum strukturell)
+   *     nicht in der rechten Struktur vorhanden ist, so kann die linke Struktur
+   *     die rechte nicht enthalten.<br>
+   *     Beim Vergleich der Attribute wird wiederum auf strukturelle Implikation
+   *     geprueft:
+   *     <ul>
+   *     <li>Handelt es sich um zwei strukturierte Attribute, muss das "linke"
+   *         Attribut das "rechte" strukturell umfassen (Rekursion!).</li>
+   *     <li>Handelt es sich um zwei statische Attribute (Typ <code>Class</code>),
+   *         muss die "linke" Klasse eine Spezialisierung (Ableitung) der
+   *         "rechten" Klasse sein.</li>
+   *     <li>Treffen beide Bedingungen nicht zu, kann das linke Attribut das
+   *         rechte nicht umfassen.<li>
+   *     </ul></li>
+   * </ol>
+   * @param o1 "linke" Objekt-Struktur
+   * @param o2 "rechte" Objekt-Struktur
+   */
+  public static boolean checkStructureContainsStructure(ObjectStructure o1, ObjectStructure o2) {
+    if ( o1.containsMultipleValues() != o2.containsMultipleValues() ||
+         o2.getAttrCount() > o1.getAttrCount() )
+      return false;
+
+    // Pruefen, ob fuer jedes Attribut in o2 ein Attribut in o1 vorhanden ist,
+    //  welches o2 beinhaltet
+    for (Enumeration attr2 = o2.getAttrTypes(); attr2.hasMoreElements();)
+      if ( !findAttrTypeInStrcucture(attr2.nextElement(),o1) )
+        return false;
+
+    return true;
+  }
+
+  /**
+   * Prueft, ob ein Attribut in einer Objekt-Struktur (strukturell) enthalten ist.
+   * Erlaeuterungen ueber die Vorgehensweise sind in der Dokumenation zu
+   * {@link #checkStructureContainsStructure(ObjectStructure,ObjectStructure)}
+   * zu finden.
+   * @param type1 Attribut (<code>ObjectStructure</code>- oder
+   *              <code>Class</code>-Instanz)
+   * @param o2    Objekt-Struktur
+   */
+  private static boolean findAttrTypeInStrcucture(Object type1, ObjectStructure o2) {
+    for (Enumeration attr2 = o2.getAttrTypes(); attr2.hasMoreElements();) {
+      Object type2 = attr2.hasMoreElements();
+
+      // wenn es sich bei beiden um Strukturen handelt und Typ2 den gesuchten
+      // Typ1 impliziert, wurde Typ1 in der Struktur o2 gefunden
+      if (type1 instanceof ObjectStructure &&
+          type2 instanceof ObjectStructure &&
+          checkStructureContainsStructure((ObjectStructure)type2,(ObjectStructure)type1) )
+        return true;
+
+      // wenn es sich bei beiden um einfache Klassen handelt und Typ2 den gesuchten
+      // Typ1 impliziert, wurde Typ1 in der Struktur o2 gefunden
+      else if (type1 instanceof Class &&
+               type2 instanceof Class &&
+               ((Class)type2).isAssignableFrom((Class)type1) )
+             return true;
+    }
+
+    return false;
+  }
+
+}

Modified: trunk/src/schmitzm/data/RasterCalculator.java
===================================================================
--- trunk/src/schmitzm/data/RasterCalculator.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/RasterCalculator.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,91 +1,109 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+/**
+ * Diese Klasse implementiert Rechen-Operationen auf Rastern.
+ * @see RasterOperationTree
+ * @see RasterOperationTreeParser
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class RasterCalculator {
+  /////////////////////////////////////////////////////////////////////
+  /////////////////////   FORMEL AUSFUEHREN   /////////////////////////
+  /////////////////////////////////////////////////////////////////////
+  /**
+   * Berechnet eine Formel auf jeder Zelle der Eingabe-Raster und speichert das
+   * Ergebnis in der jeweiligen Zelle des Ausgabe-Rasters. Hierfuer wird der
+   * Formel-String durch den {@link RasterOperationTreeParser} in einen
+   * {@link RasterOperationTree} umgewandelt, der auf dann fuer jede Rasterzelle
+   * des Output-Rasters ausgewertet wird.
+   * @param rule       Formel
+   * @param inRaster   Eingabe-Raster
+   * @param inFilter   Eingabe-Filter
+   * @param outRaster  Ausgabe-Raster
+   * @see RasterOperationTreeParser
+   */
+  public static void calculate(String rule, ReadableGrid[] inRaster, RasterFilter[] inFilter, WritableGrid outRaster ) {
+    RasterOperationTree opTree = new RasterOperationTreeParser().parse(rule);
+    if ( opTree == null )
+      return;
 
-package schmitzm.data;
-
-
-/**
- * Diese Klasse implementiert Rechen-Operationen auf Rastern.
- * @see RasterOperationTree
- * @see RasterOperationTreeParser
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class RasterCalculator {
-  /////////////////////////////////////////////////////////////////////
-  /////////////////////   FORMEL AUSFUEHREN   /////////////////////////
-  /////////////////////////////////////////////////////////////////////
-  /**
-   * Berechnet eine Formel auf jeder Zelle der Eingabe-Raster und speichert das
-   * Ergebnis in der jeweiligen Zelle des Ausgabe-Rasters. Hierfuer wird der
-   * Formel-String durch den {@link RasterOperationTreeParser} in einen
-   * {@link RasterOperationTree} umgewandelt, der auf dann fuer jede Rasterzelle
-   * des Output-Rasters ausgewertet wird.
-   * @param rule       Formel
-   * @param inRaster   Eingabe-Raster
-   * @param inFilter   Eingabe-Filter
-   * @param outRaster  Ausgabe-Raster
-   * @see RasterOperationTreeParser
-   */
-  public static void calculate(String rule, ReadableGrid[] inRaster, RasterFilter[] inFilter, WritableGrid outRaster ) {
-    RasterOperationTree opTree = new RasterOperationTreeParser().parse(rule);
-    if ( opTree == null )
-      return;
-
-    int minX = outRaster.getMinX();
-    int minY = outRaster.getMinY();
-    int maxX = minX + outRaster.getWidth() - 1;
-    int maxY = minY + outRaster.getHeight() - 1;
-
-    for (int y=minY; y<=maxY; y++)
-      for (int x=minX; x<=maxX; x++) {
-        // Berechnung starten mit dem ersten Operand
-        double result = opTree.evaluate( x, y, inRaster, inFilter );
-        outRaster.setRasterSample( (float)result, x, y );
-      }
-  }
-
-  /**
-   * Berechnet eine Formel auf jeder Zelle der Eingabe-Raster und speichert das
-   * Ergebnis in der jeweiligen Zelle des Ausgabe-Rasters. Hierfuer wird der
-   * Formel-String durch den {@link RasterOperationTreeParser} in einen
-   * {@link RasterOperationTree} umgewandelt, der auf dann fuer jede Rasterzelle
-   * des Output-Rasters ausgewertet wird.
-   * @param rule      Formel
-   * @param inRaster  Eingabe-Raster
-   * @param outRaster Ausgabe-Raster
-   * @see RasterOperationTreeParser
-   */
-  public static void calculate(String rule, ReadableGrid[] inRaster, WritableGrid outRaster ) {
-    calculate( rule, inRaster, null, outRaster);
-  }
-  /**
-   * Prueft die Syntax einer Raster-Formel auf Korrektheit.
-   * @param rule Raster-Formel.
-   */
-  public static boolean checkRule(String rule) {
-    try {
-      checkRuleAndError(rule);
-    } catch( Exception err ) {
-      return false;
-    }
-    return true;
-  }
-
-  /**
-   * Prueft die Syntax einer Raster-Formel auf Korrektheit.
-   * @param rule Raster-Formel.
-   * @exception IllegalArgumentException bei einem Fehler
-   */
-  public static void checkRuleAndError(String rule) {
-    new RasterOperationTreeParser().parse(rule);
-  }
-}
+    int minX = outRaster.getMinX();
+    int minY = outRaster.getMinY();
+    int maxX = minX + outRaster.getWidth() - 1;
+    int maxY = minY + outRaster.getHeight() - 1;
+
+    for (int y=minY; y<=maxY; y++)
+      for (int x=minX; x<=maxX; x++) {
+        // Berechnung starten mit dem ersten Operand
+        double result = opTree.evaluate( x, y, inRaster, inFilter );
+        outRaster.setRasterSample( (float)result, x, y );
+      }
+  }
+
+  /**
+   * Berechnet eine Formel auf jeder Zelle der Eingabe-Raster und speichert das
+   * Ergebnis in der jeweiligen Zelle des Ausgabe-Rasters. Hierfuer wird der
+   * Formel-String durch den {@link RasterOperationTreeParser} in einen
+   * {@link RasterOperationTree} umgewandelt, der auf dann fuer jede Rasterzelle
+   * des Output-Rasters ausgewertet wird.
+   * @param rule      Formel
+   * @param inRaster  Eingabe-Raster
+   * @param outRaster Ausgabe-Raster
+   * @see RasterOperationTreeParser
+   */
+  public static void calculate(String rule, ReadableGrid[] inRaster, WritableGrid outRaster ) {
+    calculate( rule, inRaster, null, outRaster);
+  }
+  /**
+   * Prueft die Syntax einer Raster-Formel auf Korrektheit.
+   * @param rule Raster-Formel.
+   */
+  public static boolean checkRule(String rule) {
+    try {
+      checkRuleAndError(rule);
+    } catch( Exception err ) {
+      return false;
+    }
+    return true;
+  }
+
+  /**
+   * Prueft die Syntax einer Raster-Formel auf Korrektheit.
+   * @param rule Raster-Formel.
+   * @exception IllegalArgumentException bei einem Fehler
+   */
+  public static void checkRuleAndError(String rule) {
+    new RasterOperationTreeParser().parse(rule);
+  }
+}

Modified: trunk/src/schmitzm/data/RasterFilter.java
===================================================================
--- trunk/src/schmitzm/data/RasterFilter.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/RasterFilter.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,180 +1,198 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.data;
-
-/**
- * Diese Klasse stellt eine (2-dimensionale) Filter-Matrix dar. Diese muss
- * in beiden Dimensionen eine ungerade Laenge haben, damit die Filter-Matrix
- * ein eindeutiges Zentrum besitzt.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class RasterFilter {
-  /** Speichert die Filter-Matrix. */
-  protected double[][] filter = null;
-  /** Speichert die horizontale Laenge der Filter-Matrix. */
-  protected int sizeX;
-  /** Speichert die vertikale Laenge der Filter-Matrix. */
-  protected int sizeY;
-  /** Speichert die Summe ueber alle Eintraege der Filter-Matrix. */
-  protected double weight;
-
-  /**
-   * Erzeugt einen neuen Raster-Filter. Die Filter-Matrix muss ein eindeutiges
-   * Zentrum haben, d.h. die Array-Dimensionen muessen ungerade Laenge haben!
-   * @param filter Filter-Matrix
-   */
-  public RasterFilter(double[][] filter) {
-    if ( filter == null )
-      throw new UnsupportedOperationException("null-Filter not allowed!");
-    if ( filter.length % 2 != 1 || filter[0].length % 2 != 1 )
-      throw new UnsupportedOperationException("Filter size must be odd in each dimension!");
-    for (double[] filterCol : filter)
-      if ( filterCol.length != filter[0].length )
-        throw new UnsupportedOperationException("Filter must have the same size in each column!");
-
-    this.filter = filter;
-    this.sizeX  = filter.length;
-    this.sizeY  = filter[0].length;
-    this.weight = calcFilterWeight();
-  }
-
-  /**
-   * Erzeugt einen leeren Raster-Filter. {@code sizeX} und {@code sizeY}
-   * muessen ungerade sein, damit die Filter-Matrix ein eindeutiges Zentrum hat.
-   * @param sizeX horizontale Laenge der Filter-Matrix
-   * @param sizeY vertikale Laenge der Filter-Matrix
-   */
-  public RasterFilter(int sizeX, int sizeY) {
-    this( new double[sizeX][sizeY] );
-  }
-
-  /**
-   * Erzeugt einen leeren quadratischen Raster-Filter. {@code size} muss
-   * ungerade sein, damit die Filter-Matrix ein eindeutiges Zentrum hat.
-   * @param size horizontale/vertikale Laenge der Filter-Matrix
-   */
-  public RasterFilter(int size) {
-    this( size, size );
-  }
-
-  /**
-   * Liefert die horizontale Laenge der Filter-Matrix.
-   */
-  public int getFilterSizeX() {
-    return sizeX;
-  }
-
-  /**
-   * Liefert die vertikale Laenge der Filter-Matrix.
-   */
-  public int getFilterSizeY() {
-    return sizeY;
-  }
-
-  /**
-   * Liefert die Summe ueber alle Eintraege der Filter-Matrix.
-   */
-  public double getFilterWeight() {
-    return weight;
-  }
-
-  /**
-   * Berechnet die Summe ueber alle Eintraege der Filter-Matrix.
-   */
-  public double calcFilterWeight() {
-    double sum = 0;
-    for (double[] filterCol : filter)
-      for (double v : filterCol)
-        sum += v;
-    return sum;
-  }
-
-  /**
-   * Liefert einen Wert der Filter-Matrix.
-   * @param x X-Koorindinate
-   * @param y Y-Koordinate
-   */
-  public double getFilterValue(int x, int y) {
-    return filter[x][y];
-  }
-
-  /**
-   * Setzt einen Wert der Filter-Matrix und berechnet das
-   * {@linkplain #getFilterWeight() Filter-Gewicht} neu.
-   * @param value neuer Wert
-   * @param x X-Koorindinate
-   * @param y Y-Koordinate
-   */
-  public void setFilterValue(double value, int x, int y) {
-    weight -= filter[x][y]; // Gesamtsumme um alten Wert reduzieren
-    filter[x][y] = value;
-    weight += value; // Gesamtsumme um neuen Wert erhoehen
-  }
-
-  /**
-   * Wertet den Filter auf einer Rasterzelle aus, in dem die Summe der mit
-   * den Filterwerten gewichteten Rasterwerte (um die Rasterzelle) gebildet
-   * wird und diese mit der Summe der Filterwerte normiert wird (geteilt wird).
-   * Am Rand des Rasters wird so verfahren, dass die Zellen ausserhalb des
-   * Rasters ignoriert werden, sowohl in der gewichteten Summe, als auch in
-   * der Filter-Summe.
-   * @param raster Raster
-   * @param x      X-Koordinate im Raster (Spaltenindex)
-   * @param y      Y-Koordinate im Raster (Zeilenindex)
-   * @return {@code Double.NaN} falls die Rasterzelle diesen Wert besitzt
-   * @exception IllegalArgumentException falls ein {@code null}-Raster uebergeben wird
-   *            oder die Koordinate ausserhalb des Rasters liegt
-   */
-  public double evaluate(ReadableGrid raster, int x, int y) {
-    if ( raster == null )
-      throw new IllegalArgumentException("Filter can not be evaluated on null-Raster!");
-
-    // Aus Performanzgruenden werden moeglichst alle Berechnungen nur
-    // einmal durchgefuehrt!
-    final int minX = raster.getMinX();
-    final int maxX = raster.getMinX() + raster.getWidth() - 1;
-    final int minY = raster.getMinY();
-    final int maxY = raster.getMinY() + raster.getHeight() - 1;
-    if ( x < minX || x > maxX || y < minY || y > maxY )
-      throw new IllegalArgumentException("Cell ("+x+"/"+y+") out of raster!");
-    if ( Double.isNaN( raster.getRasterSampleAsDouble(x,y) ) )
-      return Double.NaN;
-
-    // Erste relevate Raster-Koordinate
-    final int startX = x - sizeX/2;
-    final int startY = y - sizeY/2;
-
-    // Filter ueber Raster legen und Summen berechnen
-    double filterSum   = 0; // Summe der tatsaechlich verwendeten Filterwerte (RAND!!)
-    double cellSum     = 0; // Mit Filter gewichtete Summe der Rasterzellen
-    int    cellX       = 0; // betrachtete X-Koordinate im Raster
-    int    cellY       = 0; // betrachtete Y-Koordinate im Raster
-    double cellValue   = 0; // Wert der betrachteten Zelle
-    double filterValue = 0; // Wert der betrachteten Filter-Zelle
-    for (int fy = 0; fy < sizeY; fy++) {
-      cellY = startY + fy; // Raster-Koordinate
-      if ( cellY >= minY && cellY <= maxY )
-        for (int fx = 0; fx < sizeX; fx++) {
-          cellX       = startX + fx; // Raster-Koordinate
-          cellValue   = raster.getRasterSampleAsDouble(cellX,cellY);
-          filterValue = filter[fx][fy];
-          if ( cellX >= minX && cellX <= maxX && filterValue != 0 && !Double.isNaN(cellValue) ) {
-            filterSum += filterValue;
-            cellSum   += filterValue * cellValue;
-          }
-        }
-    }
-    // "Gefilterter" Zellenwert
-    return (filterSum == 0) ? 0.0 : cellSum / filterSum;
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data;
+
+/**
+ * Diese Klasse stellt eine (2-dimensionale) Filter-Matrix dar. Diese muss
+ * in beiden Dimensionen eine ungerade Laenge haben, damit die Filter-Matrix
+ * ein eindeutiges Zentrum besitzt.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class RasterFilter {
+  /** Speichert die Filter-Matrix. */
+  protected double[][] filter = null;
+  /** Speichert die horizontale Laenge der Filter-Matrix. */
+  protected int sizeX;
+  /** Speichert die vertikale Laenge der Filter-Matrix. */
+  protected int sizeY;
+  /** Speichert die Summe ueber alle Eintraege der Filter-Matrix. */
+  protected double weight;
+
+  /**
+   * Erzeugt einen neuen Raster-Filter. Die Filter-Matrix muss ein eindeutiges
+   * Zentrum haben, d.h. die Array-Dimensionen muessen ungerade Laenge haben!
+   * @param filter Filter-Matrix
+   */
+  public RasterFilter(double[][] filter) {
+    if ( filter == null )
+      throw new UnsupportedOperationException("null-Filter not allowed!");
+    if ( filter.length % 2 != 1 || filter[0].length % 2 != 1 )
+      throw new UnsupportedOperationException("Filter size must be odd in each dimension!");
+    for (double[] filterCol : filter)
+      if ( filterCol.length != filter[0].length )
+        throw new UnsupportedOperationException("Filter must have the same size in each column!");
+
+    this.filter = filter;
+    this.sizeX  = filter.length;
+    this.sizeY  = filter[0].length;
+    this.weight = calcFilterWeight();
+  }
+
+  /**
+   * Erzeugt einen leeren Raster-Filter. {@code sizeX} und {@code sizeY}
+   * muessen ungerade sein, damit die Filter-Matrix ein eindeutiges Zentrum hat.
+   * @param sizeX horizontale Laenge der Filter-Matrix
+   * @param sizeY vertikale Laenge der Filter-Matrix
+   */
+  public RasterFilter(int sizeX, int sizeY) {
+    this( new double[sizeX][sizeY] );
+  }
+
+  /**
+   * Erzeugt einen leeren quadratischen Raster-Filter. {@code size} muss
+   * ungerade sein, damit die Filter-Matrix ein eindeutiges Zentrum hat.
+   * @param size horizontale/vertikale Laenge der Filter-Matrix
+   */
+  public RasterFilter(int size) {
+    this( size, size );
+  }
+
+  /**
+   * Liefert die horizontale Laenge der Filter-Matrix.
+   */
+  public int getFilterSizeX() {
+    return sizeX;
+  }
+
+  /**
+   * Liefert die vertikale Laenge der Filter-Matrix.
+   */
+  public int getFilterSizeY() {
+    return sizeY;
+  }
+
+  /**
+   * Liefert die Summe ueber alle Eintraege der Filter-Matrix.
+   */
+  public double getFilterWeight() {
+    return weight;
+  }
+
+  /**
+   * Berechnet die Summe ueber alle Eintraege der Filter-Matrix.
+   */
+  public double calcFilterWeight() {
+    double sum = 0;
+    for (double[] filterCol : filter)
+      for (double v : filterCol)
+        sum += v;
+    return sum;
+  }
+
+  /**
+   * Liefert einen Wert der Filter-Matrix.
+   * @param x X-Koorindinate
+   * @param y Y-Koordinate
+   */
+  public double getFilterValue(int x, int y) {
+    return filter[x][y];
+  }
+
+  /**
+   * Setzt einen Wert der Filter-Matrix und berechnet das
+   * {@linkplain #getFilterWeight() Filter-Gewicht} neu.
+   * @param value neuer Wert
+   * @param x X-Koorindinate
+   * @param y Y-Koordinate
+   */
+  public void setFilterValue(double value, int x, int y) {
+    weight -= filter[x][y]; // Gesamtsumme um alten Wert reduzieren
+    filter[x][y] = value;
+    weight += value; // Gesamtsumme um neuen Wert erhoehen
+  }
+
+  /**
+   * Wertet den Filter auf einer Rasterzelle aus, in dem die Summe der mit
+   * den Filterwerten gewichteten Rasterwerte (um die Rasterzelle) gebildet
+   * wird und diese mit der Summe der Filterwerte normiert wird (geteilt wird).
+   * Am Rand des Rasters wird so verfahren, dass die Zellen ausserhalb des
+   * Rasters ignoriert werden, sowohl in der gewichteten Summe, als auch in
+   * der Filter-Summe.
+   * @param raster Raster
+   * @param x      X-Koordinate im Raster (Spaltenindex)
+   * @param y      Y-Koordinate im Raster (Zeilenindex)
+   * @return {@code Double.NaN} falls die Rasterzelle diesen Wert besitzt
+   * @exception IllegalArgumentException falls ein {@code null}-Raster uebergeben wird
+   *            oder die Koordinate ausserhalb des Rasters liegt
+   */
+  public double evaluate(ReadableGrid raster, int x, int y) {
+    if ( raster == null )
+      throw new IllegalArgumentException("Filter can not be evaluated on null-Raster!");
+
+    // Aus Performanzgruenden werden moeglichst alle Berechnungen nur
+    // einmal durchgefuehrt!
+    final int minX = raster.getMinX();
+    final int maxX = raster.getMinX() + raster.getWidth() - 1;
+    final int minY = raster.getMinY();
+    final int maxY = raster.getMinY() + raster.getHeight() - 1;
+    if ( x < minX || x > maxX || y < minY || y > maxY )
+      throw new IllegalArgumentException("Cell ("+x+"/"+y+") out of raster!");
+    if ( Double.isNaN( raster.getRasterSampleAsDouble(x,y) ) )
+      return Double.NaN;
+
+    // Erste relevate Raster-Koordinate
+    final int startX = x - sizeX/2;
+    final int startY = y - sizeY/2;
+
+    // Filter ueber Raster legen und Summen berechnen
+    double filterSum   = 0; // Summe der tatsaechlich verwendeten Filterwerte (RAND!!)
+    double cellSum     = 0; // Mit Filter gewichtete Summe der Rasterzellen
+    int    cellX       = 0; // betrachtete X-Koordinate im Raster
+    int    cellY       = 0; // betrachtete Y-Koordinate im Raster
+    double cellValue   = 0; // Wert der betrachteten Zelle
+    double filterValue = 0; // Wert der betrachteten Filter-Zelle
+    for (int fy = 0; fy < sizeY; fy++) {
+      cellY = startY + fy; // Raster-Koordinate
+      if ( cellY >= minY && cellY <= maxY )
+        for (int fx = 0; fx < sizeX; fx++) {
+          cellX       = startX + fx; // Raster-Koordinate
+          cellValue   = raster.getRasterSampleAsDouble(cellX,cellY);
+          filterValue = filter[fx][fy];
+          if ( cellX >= minX && cellX <= maxX && filterValue != 0 && !Double.isNaN(cellValue) ) {
+            filterSum += filterValue;
+            cellSum   += filterValue * cellValue;
+          }
+        }
+    }
+    // "Gefilterter" Zellenwert
+    return (filterSum == 0) ? 0.0 : cellSum / filterSum;
+  }
+}

Modified: trunk/src/schmitzm/data/RasterOperationTree.java
===================================================================
--- trunk/src/schmitzm/data/RasterOperationTree.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/RasterOperationTree.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,276 +1,294 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.data;
-
-import schmitzm.lang.tree.BinaryTreeNode;
-import schmitzm.lang.tree.OperationTree;
-import schmitzm.lang.tree.TreeNode;
-
-/**
- * Diese Klasse stellt einen Operator-Baum dar, in dem neben den von der
- * Oberklasse definitierten Operationen, Referenzen auf Raster und Filter
- * enthalten sein koennen.<br>
- * Der Operator-Baum wird auf einer bestimmten Raster-Koordinate ausgewertet.<br>
- * <br>
- * <b>Raster-Referenz:</b> {@link RasterReferenceNode}<br>
- * Eine Raster-Referenz wird durch einen {@code int}-Wert dargestellt, der von
- * einem {@code #} eingeleitet wird (z.B. {@code #0}). Bei der Auswertung des Operatorbaums
- * (auf einer bestimmten Raster-Koordinate) wird diese Referenz durch den
- * entsprechenden Zell-Wert des referenzierten Rasters ersetzt.<br>
- * <br>
- * <b>Filter-Referenz:</b> {@link FilterReferenceNode}<br>
- * Eine Filter-Referenz wird durch einen {@code int}-Wert dargestellt, der von
- * einem {@code F} eingeleitet wird (z.B. {@code F1(.)}) Die Auswertung eines
- * Filters kann nur direkt auf einer Raster-Referenz erfolgen, da ansonsten
- * keine zellen-weise Abarbeitung des Rasters mehr moeglich ist, sondern
- * komplette Raster als Zwischenergebnisse ausgewertet werden muessten.<br>
- * <b>Koordinaten-Referenz:</b> {@code X} oder {@code Y}<br>
- * Stellt einen Alias fuer die X- bzw. Y-Koordinate der Rasterzelle dar, die
- * verarbeitet wird.<br>
- * <b>NoData:</b> Konstante {@code NoData} und Funktion {@code isNoData(.)}<br>
- * Stellen einen Alias fuer {@code NaN}, bzw. {@code isNaN(.)} dar.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class RasterOperationTree extends OperationTree {
-  private int                x           = 0;
-  private int                y           = 0;
-  private ReadableGrid[]     inputRaster = null;
-  private RasterFilter[]     inputFilter = null;
-
-  /**
-   * Erzeugt einen neuen Raster-Operatorbaum
-   * @param root Wurzelknoten
-   */
-  public RasterOperationTree(TreeNode root) {
-    super(root);
-  }
-
-  /**
-   * Nicht unterstuetzt!
-   * @deprecated
-   * @exception UnsupportedOperationException bei jedem Aufruf
-   */
-  public Object evaluate() {
-    throw new UnsupportedOperationException("RasterOperationTree only supports evaluate(ReadableGrid[],int,int)");
-  }
-
-  /**
-   * Wertet den Operatorbaum auf einer bestimmten Raster-Koordinate aus.
-   * @param x X-Koordinate
-   * @param y Y-Koordinate
-   * @param inputRaster Eingabe-Raster auf die die #-Referenzen gemappt werden
-   * @param inputFilter Eingabe-Filter auf die die F-Referenzen gemappt werden
-   */
-  public Double evaluate(int x, int y, ReadableGrid[] inputRaster, RasterFilter[] inputFilter) {
-    this.x = x;
-    this.y = y;
-    this.inputRaster = inputRaster;
-    this.inputFilter = inputFilter;
-    Object result = super.evaluate();
-    if ( result instanceof Boolean )
-      result = (Boolean)result ? 1 : 0;
-    if ( !(result instanceof Number) )
-      throw new UnsupportedOperationException( DataUtil.RESOURCE.getString("RasterOperationTree.err.NonNumericResult", result) );
-    return ((Number)result).doubleValue();
-  }
-
-  /**
-   * Wertet den Operatorbaum auf einer bestimmten Raster-Koordinate aus.
-   * @param x X-Koordinate
-   * @param y Y-Koordinate
-   * @param inputRaster Eingabe-Raster auf die die Referenzen gemappt werden
-   */
-  public Double evaluate(int x, int y, ReadableGrid[] inputRaster) {
-    return evaluate(x,y,inputRaster);
-  }
-
-  /**
-   * Wertet einen Knoten des Operator-Baums aus.
-   * @param opTreeNode BinaryTreeNode
-   * @return double
-   */
-  protected Object evaluate(TreeNode opTreeNode) {
-    // Referenznummer auf Raster
-    if ( opTreeNode instanceof RasterReferenceNode )
-      return getInputRaster( ((RasterReferenceNode)opTreeNode).getObject() ).getRasterSampleAsDouble(x, y);
-
-    // Referenznummer auf Filter
-    if ( opTreeNode instanceof FilterReferenceNode ) {
-      FilterReferenceNode filterRefereceNode = (FilterReferenceNode)opTreeNode;
-      RasterFilter   filter      = getInputFilter( filterRefereceNode.getFilterNumber() );
-      BinaryTreeNode operandNode = filterRefereceNode.getLeftChild();
-      if ( !(operandNode instanceof RasterOperationTree.RasterReferenceNode) )
-        throw new UnsupportedOperationException( DataUtil.RESOURCE.getString("RasterOperationTree.err.FilterReferenceNotAllowed") );
-      ReadableGrid   raster      = getInputRaster( ((RasterReferenceNode)operandNode).getObject() );
-      return filter.evaluate(raster,x, y);
-    }
-    return super.evaluate(opTreeNode);
-  }
-
-  /**
-   * Wertet einen 1-stelligen Operator aus.
-   * Erweitert die Methode der Oberklasse, um die folgenden Operatoren:
-   * <ul>
-   *   <li>{@code isNoData(.)}: Alias fuer die Funktion "isNaN(.)"</li>
-   * </ul>
-   * @param operator 1-stelliger Operator
-   * @param operand  Operand auf den der Operator angewendet wird
-   * @return <i>operator</li>( {@code operand} )
-   */
-  protected Double performOperation(String operator, Object operand) {
-    operator = operator.toUpperCase();
-    if ( operator.equals("ISNODATA") )
-      operator = "ISNAN";
-
-    Object result = super.performOperation(operator,operand);
-    return result instanceof Number ? ((Number)result).doubleValue() : 0.0;
-  }
-
-  /**
-   * Wertet einen 0-stelligen Operator (Alias oder Variable) aus.
-   * Erweitert die Methode der Oberklasse, um die folgenden Operatoren:
-   * <ul>
-   *   <li>{@code X}: Alias fuer die horizontale Raster-Koordinate</li>
-   *   <li>{@code Y}: Alias fuer die vertikale Raster-Koordinate</li>
-   *   <li>{@code NoData}: Alias fuer die Konstante "NaN"</li>
-   * </ul>
-   * @param operator 0-stelliger Operator
-   */
-  protected Double performOperation(String operator) {
-    operator = operator.toUpperCase();
-
-    if ( operator.equalsIgnoreCase("X") )
-      return Double.valueOf(x);
-    if ( operator.equalsIgnoreCase("Y") )
-      return Double.valueOf(y);
-    if ( operator.equals("NODATA") )
-      operator = "NAN";
-
-    Object result = super.performOperation(operator);
-    return result instanceof Number ? ((Number)result).doubleValue() : 0.0;
-  }
-
-  /**
-   * Liefert eines der zur Verfuegung stehenden Eingabe-Raster.
-   * @param rasterNo Raster-Nummer
-   * @exception IllegalArgumentException falls eine ungueltige Raster-Nummer
-   *            uebergeben wird
-   */
-  private ReadableGrid getInputRaster(int rasterNo) {
-    if ( rasterNo >= inputRaster.length ) {
-      String allowedStr = ( inputRaster.length > 0 ) ? DataUtil.RESOURCE.getString( "RasterOperationTree.err.AllowedIdx", inputRaster.length-1 )
-                                                     : DataUtil.RESOURCE.getString( "RasterOperationTree.err.NoneAllowed");
-      throw new IllegalArgumentException( DataUtil.RESOURCE.getString("RasterOperationTree.err.InvalidRasterReference",rasterNo,allowedStr) ); 
-    }
-    return inputRaster[rasterNo];
-  }
-
-  /**
-   * Liefert einen der zur Verfuegung stehenden Eingabe-Filter.
-   * @param rasterNo Filter-Nummer
-   * @exception IllegalArgumentException falls eine ungueltige Filter-Nummer
-   *            uebergeben wird
-   */
-  private RasterFilter getInputFilter(int filterNo) {
-    if ( filterNo >= inputFilter.length ) {
-      String allowedStr = ( inputFilter.length > 0 ) ? DataUtil.RESOURCE.getString( "RasterOperationTree.err.AllowedIdx", inputFilter.length-1 )
-                                                     : DataUtil.RESOURCE.getString( "RasterOperationTree.err.NoneAllowed");
-      throw new IllegalArgumentException( DataUtil.RESOURCE.getString("RasterOperationTree.err.InvalidFilterReference",inputFilter,allowedStr) ); 
-    }
-    return inputFilter[filterNo];
-  }
-
-
-  /**
-   * Diese Knoten repraesentiert eine Referenz auf ein Raster im Operatorbaum.
-   * Da es sich bei einem Zellwert um eine Konstante handelt, hat der Knoten
-   * keine Kind-Knoten. Die Referenz wird durch einen {@code int} dargestellt.
-   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-   * @version 1.0
-   */
-  public static class RasterReferenceNode extends BinaryTreeNode<Integer> {
-    /**
-     * Erzeugt einen neuen Referenz-Knoten
-     * @param rasterNo Referenz-Nummer
-     * @param parent   Vater-Knoten
-     */
-    public RasterReferenceNode(int rasterNo, BinaryTreeNode parent) {
-      super(rasterNo, parent);
-    }
-
-    /**
-     * Erzeugt einen neuen Referenz-Knoten
-     * @param rasterNo Referenz-Nummer
-     */
-    public RasterReferenceNode(int rasterNo) {
-      this(rasterNo, null);
-    }
-
-    /**
-     * Macht nichts, da {@code RasterReferenceNode} immer einen Blatt-Knoten
-     * darstellt.
-     * @param i Index (beginnend bei 0)
-     * @param child neuer Kind-Knoten
-     */
-    public void setChild(int i, TreeNode<Integer> child) {
-    }
-  }
-
-  /**
-   * Diese Knoten repraesentiert eine Referenz auf einen Filter im Operatorbaum.
-   * Als Operator-Kennzeichen wird "F" verwendet. Die Referenz auf den Filter
-   * wird in einem zusaetzlichen {@code int}-Wert gespeichert.
-   * @see #getFilterNumber()
-   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-   * @version 1.0
-   */
-  public static class FilterReferenceNode extends OperationTree.UnaryOperatorNode {
-    /** Speichert die Referenznummer auf den Filter. */
-    protected int filterNo = 0;
-
-    /**
-     * Erzeugt einen neuen Referenz-Knoten
-     * @param filterNo Referenz-Nummer
-     * @param parent   Vater-Knoten
-     * @param operand  Knoten der den (linker) Operand repraesentiert
-     */
-    public FilterReferenceNode(int filterNo, BinaryTreeNode parent, BinaryTreeNode operand) {
-      super("F", parent, operand);
-      setFilterNumber( filterNo );
-    }
-
-    /**
-     * Erzeugt einen neuen Referenz-Knoten
-     * @param filterNo Referenz-Nummer
-     * @param operand  Knoten der den (linker) Operand repraesentiert
-     */
-    public FilterReferenceNode(int filterNo, BinaryTreeNode operand) {
-      this(filterNo, null, operand);
-    }
-
-    /**
-     * Setzt die Referenznummer auf einen Filter.
-     * @param filterNo Referenznummer auf einen Filter
-     */
-    public void setFilterNumber(int filterNo) {
-      this.filterNo = filterNo;
-    }
-
-    /**
-     * Liefert die Referenznummer auf einen Filter.
-     */
-    public int getFilterNumber() {
-      return filterNo;
-    }
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data;
+
+import schmitzm.lang.tree.BinaryTreeNode;
+import schmitzm.lang.tree.OperationTree;
+import schmitzm.lang.tree.TreeNode;
+
+/**
+ * Diese Klasse stellt einen Operator-Baum dar, in dem neben den von der
+ * Oberklasse definitierten Operationen, Referenzen auf Raster und Filter
+ * enthalten sein koennen.<br>
+ * Der Operator-Baum wird auf einer bestimmten Raster-Koordinate ausgewertet.<br>
+ * <br>
+ * <b>Raster-Referenz:</b> {@link RasterReferenceNode}<br>
+ * Eine Raster-Referenz wird durch einen {@code int}-Wert dargestellt, der von
+ * einem {@code #} eingeleitet wird (z.B. {@code #0}). Bei der Auswertung des Operatorbaums
+ * (auf einer bestimmten Raster-Koordinate) wird diese Referenz durch den
+ * entsprechenden Zell-Wert des referenzierten Rasters ersetzt.<br>
+ * <br>
+ * <b>Filter-Referenz:</b> {@link FilterReferenceNode}<br>
+ * Eine Filter-Referenz wird durch einen {@code int}-Wert dargestellt, der von
+ * einem {@code F} eingeleitet wird (z.B. {@code F1(.)}) Die Auswertung eines
+ * Filters kann nur direkt auf einer Raster-Referenz erfolgen, da ansonsten
+ * keine zellen-weise Abarbeitung des Rasters mehr moeglich ist, sondern
+ * komplette Raster als Zwischenergebnisse ausgewertet werden muessten.<br>
+ * <b>Koordinaten-Referenz:</b> {@code X} oder {@code Y}<br>
+ * Stellt einen Alias fuer die X- bzw. Y-Koordinate der Rasterzelle dar, die
+ * verarbeitet wird.<br>
+ * <b>NoData:</b> Konstante {@code NoData} und Funktion {@code isNoData(.)}<br>
+ * Stellen einen Alias fuer {@code NaN}, bzw. {@code isNaN(.)} dar.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class RasterOperationTree extends OperationTree {
+  private int                x           = 0;
+  private int                y           = 0;
+  private ReadableGrid[]     inputRaster = null;
+  private RasterFilter[]     inputFilter = null;
+
+  /**
+   * Erzeugt einen neuen Raster-Operatorbaum
+   * @param root Wurzelknoten
+   */
+  public RasterOperationTree(TreeNode root) {
+    super(root);
+  }
+
+  /**
+   * Nicht unterstuetzt!
+   * @deprecated
+   * @exception UnsupportedOperationException bei jedem Aufruf
+   */
+  public Object evaluate() {
+    throw new UnsupportedOperationException("RasterOperationTree only supports evaluate(ReadableGrid[],int,int)");
+  }
+
+  /**
+   * Wertet den Operatorbaum auf einer bestimmten Raster-Koordinate aus.
+   * @param x X-Koordinate
+   * @param y Y-Koordinate
+   * @param inputRaster Eingabe-Raster auf die die #-Referenzen gemappt werden
+   * @param inputFilter Eingabe-Filter auf die die F-Referenzen gemappt werden
+   */
+  public Double evaluate(int x, int y, ReadableGrid[] inputRaster, RasterFilter[] inputFilter) {
+    this.x = x;
+    this.y = y;
+    this.inputRaster = inputRaster;
+    this.inputFilter = inputFilter;
+    Object result = super.evaluate();
+    if ( result instanceof Boolean )
+      result = (Boolean)result ? 1 : 0;
+    if ( !(result instanceof Number) )
+      throw new UnsupportedOperationException( DataUtil.RESOURCE.getString("RasterOperationTree.err.NonNumericResult", result) );
+    return ((Number)result).doubleValue();
+  }
+
+  /**
+   * Wertet den Operatorbaum auf einer bestimmten Raster-Koordinate aus.
+   * @param x X-Koordinate
+   * @param y Y-Koordinate
+   * @param inputRaster Eingabe-Raster auf die die Referenzen gemappt werden
+   */
+  public Double evaluate(int x, int y, ReadableGrid[] inputRaster) {
+    return evaluate(x,y,inputRaster);
+  }
+
+  /**
+   * Wertet einen Knoten des Operator-Baums aus.
+   * @param opTreeNode BinaryTreeNode
+   * @return double
+   */
+  protected Object evaluate(TreeNode opTreeNode) {
+    // Referenznummer auf Raster
+    if ( opTreeNode instanceof RasterReferenceNode )
+      return getInputRaster( ((RasterReferenceNode)opTreeNode).getObject() ).getRasterSampleAsDouble(x, y);
+
+    // Referenznummer auf Filter
+    if ( opTreeNode instanceof FilterReferenceNode ) {
+      FilterReferenceNode filterRefereceNode = (FilterReferenceNode)opTreeNode;
+      RasterFilter   filter      = getInputFilter( filterRefereceNode.getFilterNumber() );
+      BinaryTreeNode operandNode = filterRefereceNode.getLeftChild();
+      if ( !(operandNode instanceof RasterOperationTree.RasterReferenceNode) )
+        throw new UnsupportedOperationException( DataUtil.RESOURCE.getString("RasterOperationTree.err.FilterReferenceNotAllowed") );
+      ReadableGrid   raster      = getInputRaster( ((RasterReferenceNode)operandNode).getObject() );
+      return filter.evaluate(raster,x, y);
+    }
+    return super.evaluate(opTreeNode);
+  }
+
+  /**
+   * Wertet einen 1-stelligen Operator aus.
+   * Erweitert die Methode der Oberklasse, um die folgenden Operatoren:
+   * <ul>
+   *   <li>{@code isNoData(.)}: Alias fuer die Funktion "isNaN(.)"</li>
+   * </ul>
+   * @param operator 1-stelliger Operator
+   * @param operand  Operand auf den der Operator angewendet wird
+   * @return <i>operator</li>( {@code operand} )
+   */
+  protected Double performOperation(String operator, Object operand) {
+    operator = operator.toUpperCase();
+    if ( operator.equals("ISNODATA") )
+      operator = "ISNAN";
+
+    Object result = super.performOperation(operator,operand);
+    return result instanceof Number ? ((Number)result).doubleValue() : 0.0;
+  }
+
+  /**
+   * Wertet einen 0-stelligen Operator (Alias oder Variable) aus.
+   * Erweitert die Methode der Oberklasse, um die folgenden Operatoren:
+   * <ul>
+   *   <li>{@code X}: Alias fuer die horizontale Raster-Koordinate</li>
+   *   <li>{@code Y}: Alias fuer die vertikale Raster-Koordinate</li>
+   *   <li>{@code NoData}: Alias fuer die Konstante "NaN"</li>
+   * </ul>
+   * @param operator 0-stelliger Operator
+   */
+  protected Double performOperation(String operator) {
+    operator = operator.toUpperCase();
+
+    if ( operator.equalsIgnoreCase("X") )
+      return Double.valueOf(x);
+    if ( operator.equalsIgnoreCase("Y") )
+      return Double.valueOf(y);
+    if ( operator.equals("NODATA") )
+      operator = "NAN";
+
+    Object result = super.performOperation(operator);
+    return result instanceof Number ? ((Number)result).doubleValue() : 0.0;
+  }
+
+  /**
+   * Liefert eines der zur Verfuegung stehenden Eingabe-Raster.
+   * @param rasterNo Raster-Nummer
+   * @exception IllegalArgumentException falls eine ungueltige Raster-Nummer
+   *            uebergeben wird
+   */
+  private ReadableGrid getInputRaster(int rasterNo) {
+    if ( rasterNo >= inputRaster.length ) {
+      String allowedStr = ( inputRaster.length > 0 ) ? DataUtil.RESOURCE.getString( "RasterOperationTree.err.AllowedIdx", inputRaster.length-1 )
+                                                     : DataUtil.RESOURCE.getString( "RasterOperationTree.err.NoneAllowed");
+      throw new IllegalArgumentException( DataUtil.RESOURCE.getString("RasterOperationTree.err.InvalidRasterReference",rasterNo,allowedStr) ); 
+    }
+    return inputRaster[rasterNo];
+  }
+
+  /**
+   * Liefert einen der zur Verfuegung stehenden Eingabe-Filter.
+   * @param rasterNo Filter-Nummer
+   * @exception IllegalArgumentException falls eine ungueltige Filter-Nummer
+   *            uebergeben wird
+   */
+  private RasterFilter getInputFilter(int filterNo) {
+    if ( filterNo >= inputFilter.length ) {
+      String allowedStr = ( inputFilter.length > 0 ) ? DataUtil.RESOURCE.getString( "RasterOperationTree.err.AllowedIdx", inputFilter.length-1 )
+                                                     : DataUtil.RESOURCE.getString( "RasterOperationTree.err.NoneAllowed");
+      throw new IllegalArgumentException( DataUtil.RESOURCE.getString("RasterOperationTree.err.InvalidFilterReference",inputFilter,allowedStr) ); 
+    }
+    return inputFilter[filterNo];
+  }
+
+
+  /**
+   * Diese Knoten repraesentiert eine Referenz auf ein Raster im Operatorbaum.
+   * Da es sich bei einem Zellwert um eine Konstante handelt, hat der Knoten
+   * keine Kind-Knoten. Die Referenz wird durch einen {@code int} dargestellt.
+   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+   * @version 1.0
+   */
+  public static class RasterReferenceNode extends BinaryTreeNode<Integer> {
+    /**
+     * Erzeugt einen neuen Referenz-Knoten
+     * @param rasterNo Referenz-Nummer
+     * @param parent   Vater-Knoten
+     */
+    public RasterReferenceNode(int rasterNo, BinaryTreeNode parent) {
+      super(rasterNo, parent);
+    }
+
+    /**
+     * Erzeugt einen neuen Referenz-Knoten
+     * @param rasterNo Referenz-Nummer
+     */
+    public RasterReferenceNode(int rasterNo) {
+      this(rasterNo, null);
+    }
+
+    /**
+     * Macht nichts, da {@code RasterReferenceNode} immer einen Blatt-Knoten
+     * darstellt.
+     * @param i Index (beginnend bei 0)
+     * @param child neuer Kind-Knoten
+     */
+    public void setChild(int i, TreeNode<Integer> child) {
+    }
+  }
+
+  /**
+   * Diese Knoten repraesentiert eine Referenz auf einen Filter im Operatorbaum.
+   * Als Operator-Kennzeichen wird "F" verwendet. Die Referenz auf den Filter
+   * wird in einem zusaetzlichen {@code int}-Wert gespeichert.
+   * @see #getFilterNumber()
+   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+   * @version 1.0
+   */
+  public static class FilterReferenceNode extends OperationTree.UnaryOperatorNode {
+    /** Speichert die Referenznummer auf den Filter. */
+    protected int filterNo = 0;
+
+    /**
+     * Erzeugt einen neuen Referenz-Knoten
+     * @param filterNo Referenz-Nummer
+     * @param parent   Vater-Knoten
+     * @param operand  Knoten der den (linker) Operand repraesentiert
+     */
+    public FilterReferenceNode(int filterNo, BinaryTreeNode parent, BinaryTreeNode operand) {
+      super("F", parent, operand);
+      setFilterNumber( filterNo );
+    }
+
+    /**
+     * Erzeugt einen neuen Referenz-Knoten
+     * @param filterNo Referenz-Nummer
+     * @param operand  Knoten der den (linker) Operand repraesentiert
+     */
+    public FilterReferenceNode(int filterNo, BinaryTreeNode operand) {
+      this(filterNo, null, operand);
+    }
+
+    /**
+     * Setzt die Referenznummer auf einen Filter.
+     * @param filterNo Referenznummer auf einen Filter
+     */
+    public void setFilterNumber(int filterNo) {
+      this.filterNo = filterNo;
+    }
+
+    /**
+     * Liefert die Referenznummer auf einen Filter.
+     */
+    public int getFilterNumber() {
+      return filterNo;
+    }
+  }
+}

Modified: trunk/src/schmitzm/data/RasterOperationTreeParser.java
===================================================================
--- trunk/src/schmitzm/data/RasterOperationTreeParser.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/RasterOperationTreeParser.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,104 +1,122 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.data;
-
-import schmitzm.data.RasterOperationTree.FilterReferenceNode;
-import schmitzm.data.RasterOperationTree.RasterReferenceNode;
-import schmitzm.lang.tree.BinaryTreeNode;
-import schmitzm.lang.tree.OperationTree;
-import schmitzm.lang.tree.OperationTreeParser;
-
-/**
- * Diese Klasse stellt einen Parser fuer einen {@linkplain RasterOperationTree Raster-Operatorbaum}
- * dar. Dieser erstellt einen {@linkplain RasterOperationTree Raster-Operatorbaum} aus einem
- * Formel-String, der neben den in {@link OperationTreeParser} beschriebenen
- * Komponenten Raster- und Filter-Referenzen enthalten darf.<br>
- * <br>
- * <b>Raster-Referenz:</b> {@link RasterReferenceNode}<br>
- * Eine Raster-Referenz wird durch einen {@code int}-Wert dargestellt, der von
- * einem {@code #} eingeleitet wird (z.B. {@code #0}). Bei der Auswertung des Operatorbaums
- * (auf einer bestimmten Raster-Koordinate) wird diese Referenz durch den
- * entsprechenden Zell-Wert des referenzierten Rasters ersetzt.<br>
- * <br>
- * <b>Filter-Referenz:</b> {@link FilterReferenceNode}<br>
- * Eine Filter-Referenz wird durch einen {@code int}-Wert dargestellt, der von
- * einem {@code F} eingeleitet wird (z.B. {@code F1(.)}) Die Auswertung eines Filters kann nur
- * direkt auf einer Raster-Referenz erfolgen, da ansonsten keine zellen-weise
- * Abarbeitung des Rasters mehr moeglich ist, sondern komplette Raster als
- * Zwischenergebnisse ausgewertet werden muessten.<br>
- * <b>Koordinaten-Referenz:</b> {@code X} oder {@code Y}<br>
- * Stellt einen Alias fuer die X- bzw. Y-Koordinate der Rasterzelle dar, die
- * verarbeitet wird.<br>
- * <b>NoData:</b> Konstante {@code NoData} und Funktion {@code isNoData(.)}<br>
- * Stellen einen Alias fuer {@code NaN}, bzw. {@code isNaN(.)} dar.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class RasterOperationTreeParser extends OperationTreeParser {
-  /**
-   * Erstellt einen Raster-Operator-Baum aus einem Formel-String.
-   * @param rule Formel
-   */
-  public RasterOperationTree parse(String rule) {
-    return new RasterOperationTree( super.parse(rule).getRoot() );
-  }
-
-//  /**
-//   * Liefert einen LeerString, da der Strings im RasterCalculator keinen Sinn
-//   * machen.
-//   */
-//  @Override
-//  public String getStringEncapsulationChars() {
-//    return "";
-//  }
-
-  /**
-   * Parst das naechste Literal aus dem Tokenizer {@link #tok}.
-   * Erweitert die Funktionalitaet der Oberklasse, so dass neben Konstanten
-   * auch Referenznummern auf ein Raster (eingeleitet durch {@code #}) und
-   * Referenznummern auf einen Filter (eingeleitet durch {@code F})
-   * angegeben werden koennen. Zudem koennen die Konstanten {@code X} und {@code Y}
-   * verwendet werden, um die horizontale und vertikale Raster-Koordinate zu
-   * referenzieren und {@code NoData}, bzw. {@code isNoData(.)} als Alias fuer
-   * {@code NaN}, bzw. {@code isNaN} verwendet werden.
-   */
-  protected BinaryTreeNode parseLiteral() {
-    String token = nextNonWSToken();
-
-    // Filter
-    if (token.startsWith("F")) {
-      BinaryTreeNode operandNode = parseRulePart();
-      if ( !(operandNode instanceof RasterOperationTree.RasterReferenceNode) )
-        throw new UnsupportedOperationException( DataUtil.RESOURCE.getString("RasterOperationTree.err.FilterReferenceNotAllowed") );
-      return new RasterOperationTree.FilterReferenceNode(getIntFromString(token.substring(1)),operandNode);
-    }
-
-    // Raster-Indikator
-    if (token.startsWith("#"))
-      return new RasterOperationTree.RasterReferenceNode(getIntFromString(token.substring(1)));
-
-    // X- oder Y-Koordinate, NODATA
-    if ( token.equalsIgnoreCase("X") || token.equalsIgnoreCase("Y") ||
-         token.equalsIgnoreCase("NODATA") ) {
-      return new OperationTree.ConstantAliasNode(token);
-    }
-
-    // Check auf NoData
-    if ( token.equalsIgnoreCase("ISNODATA") )
-      return new OperationTree.UnaryOperatorNode(token, parseRulePart());
-
-    // sonst: auf Literale der Oberklasse zurueckgreifen
-    pushbackWithWSToken();
-    return super.parseLiteral();
-  }
-}
-
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data;
+
+import schmitzm.data.RasterOperationTree.FilterReferenceNode;
+import schmitzm.data.RasterOperationTree.RasterReferenceNode;
+import schmitzm.lang.tree.BinaryTreeNode;
+import schmitzm.lang.tree.OperationTree;
+import schmitzm.lang.tree.OperationTreeParser;
+
+/**
+ * Diese Klasse stellt einen Parser fuer einen {@linkplain RasterOperationTree Raster-Operatorbaum}
+ * dar. Dieser erstellt einen {@linkplain RasterOperationTree Raster-Operatorbaum} aus einem
+ * Formel-String, der neben den in {@link OperationTreeParser} beschriebenen
+ * Komponenten Raster- und Filter-Referenzen enthalten darf.<br>
+ * <br>
+ * <b>Raster-Referenz:</b> {@link RasterReferenceNode}<br>
+ * Eine Raster-Referenz wird durch einen {@code int}-Wert dargestellt, der von
+ * einem {@code #} eingeleitet wird (z.B. {@code #0}). Bei der Auswertung des Operatorbaums
+ * (auf einer bestimmten Raster-Koordinate) wird diese Referenz durch den
+ * entsprechenden Zell-Wert des referenzierten Rasters ersetzt.<br>
+ * <br>
+ * <b>Filter-Referenz:</b> {@link FilterReferenceNode}<br>
+ * Eine Filter-Referenz wird durch einen {@code int}-Wert dargestellt, der von
+ * einem {@code F} eingeleitet wird (z.B. {@code F1(.)}) Die Auswertung eines Filters kann nur
+ * direkt auf einer Raster-Referenz erfolgen, da ansonsten keine zellen-weise
+ * Abarbeitung des Rasters mehr moeglich ist, sondern komplette Raster als
+ * Zwischenergebnisse ausgewertet werden muessten.<br>
+ * <b>Koordinaten-Referenz:</b> {@code X} oder {@code Y}<br>
+ * Stellt einen Alias fuer die X- bzw. Y-Koordinate der Rasterzelle dar, die
+ * verarbeitet wird.<br>
+ * <b>NoData:</b> Konstante {@code NoData} und Funktion {@code isNoData(.)}<br>
+ * Stellen einen Alias fuer {@code NaN}, bzw. {@code isNaN(.)} dar.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class RasterOperationTreeParser extends OperationTreeParser {
+  /**
+   * Erstellt einen Raster-Operator-Baum aus einem Formel-String.
+   * @param rule Formel
+   */
+  public RasterOperationTree parse(String rule) {
+    return new RasterOperationTree( super.parse(rule).getRoot() );
+  }
+
+//  /**
+//   * Liefert einen LeerString, da der Strings im RasterCalculator keinen Sinn
+//   * machen.
+//   */
+//  @Override
+//  public String getStringEncapsulationChars() {
+//    return "";
+//  }
+
+  /**
+   * Parst das naechste Literal aus dem Tokenizer {@link #tok}.
+   * Erweitert die Funktionalitaet der Oberklasse, so dass neben Konstanten
+   * auch Referenznummern auf ein Raster (eingeleitet durch {@code #}) und
+   * Referenznummern auf einen Filter (eingeleitet durch {@code F})
+   * angegeben werden koennen. Zudem koennen die Konstanten {@code X} und {@code Y}
+   * verwendet werden, um die horizontale und vertikale Raster-Koordinate zu
+   * referenzieren und {@code NoData}, bzw. {@code isNoData(.)} als Alias fuer
+   * {@code NaN}, bzw. {@code isNaN} verwendet werden.
+   */
+  protected BinaryTreeNode parseLiteral() {
+    String token = nextNonWSToken();
+
+    // Filter
+    if (token.startsWith("F")) {
+      BinaryTreeNode operandNode = parseRulePart();
+      if ( !(operandNode instanceof RasterOperationTree.RasterReferenceNode) )
+        throw new UnsupportedOperationException( DataUtil.RESOURCE.getString("RasterOperationTree.err.FilterReferenceNotAllowed") );
+      return new RasterOperationTree.FilterReferenceNode(getIntFromString(token.substring(1)),operandNode);
+    }
+
+    // Raster-Indikator
+    if (token.startsWith("#"))
+      return new RasterOperationTree.RasterReferenceNode(getIntFromString(token.substring(1)));
+
+    // X- oder Y-Koordinate, NODATA
+    if ( token.equalsIgnoreCase("X") || token.equalsIgnoreCase("Y") ||
+         token.equalsIgnoreCase("NODATA") ) {
+      return new OperationTree.ConstantAliasNode(token);
+    }
+
+    // Check auf NoData
+    if ( token.equalsIgnoreCase("ISNODATA") )
+      return new OperationTree.UnaryOperatorNode(token, parseRulePart());
+
+    // sonst: auf Literale der Oberklasse zurueckgreifen
+    pushbackWithWSToken();
+    return super.parseLiteral();
+  }
+}
+

Modified: trunk/src/schmitzm/data/ReadableGrid.java
===================================================================
--- trunk/src/schmitzm/data/ReadableGrid.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/ReadableGrid.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,216 +1,234 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.data;
-
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
 
 import appl.data.LateLoadable;
-
-/**
- * Dieses Interface stellt die Basis fuer ein georeferenziertes
- * Raster dar.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public interface ReadableGrid extends LateLoadable {
-  /**
-   * Die Dimension des Rasters (2).
-   */
-  public static final int RASTER_DIM = 2;
-
-  /**
-   * Zerstoert das Raster und gibt alle Ressourcen wieder frei.
-   */
-  public void dispose();
-
-  /**
-   * Liefert die Breite des Rasters (in Zellen).
-   */
-  public int getWidth();
-
-  /**
-   * Liefert die Hoehe des Rasters (in Zellen).
-   */
-  public int getHeight();
-
-  /**
-   * Liefert den Index der ersten (Südwest) Zelle in X-Richtung.
-   */
-  public int getMinX();
-
-  /**
-   * Liefert den Index der ersten Zelle (Südwest) in Y-Richtung.
-   */
-  public int getMinY();
-
-  /**
-   * Liefert das {@link CoordinateReferenceSystem} in dem das Raster
-   * dargestellt ist.
-   */
-  public CoordinateReferenceSystem getCoordinateReferenceSystem();
-
-  /**
-   * Liefert die reale Breite des Rasters.
-   */
-  public double getRealWidth();
-
-  /**
-   * Liefert die reale Breite des Rasters.
-   */
-  public double getRealHeight();
-
-  /**
-   * Liefert die reale Breite einer Zelle.<br>
-   * Sollte <code>{@link #getRealWidth()} / {@link #getWidth()} entsprechen!
-   */
-  public double getCellWidth();
-
-  /**
-   * Liefert die reale Hoehe einer Zelle.<br>
-   * Sollte <code>{@link #getRealHeight()} / {@link #getHeight()} entsprechen!
-   */
-  public double getCellHeight();
-
-  /**
-   * Liefert die X-Koordinate (Longitude) der Georeferenz der linken unteren Ecke des Rasters (Südwest).
-   */
-  public double getX();
-
-  /**
-   * Liefert die Y-Koordinate (Latitude) der Georeferenz der linken unteren Ecke des Rasters (Südwest).
-   */
-  public double getY();
-
-  /**
-   * Liefert die Art der Daten, die im Raster gespeichert werden koennen. Diese
-   * wird durch eine der TYPE-Konstanten in {@link java.awt.image.DataBuffer}
-   * repraesentiert.
-   */
-  public int getSampleType();
-
 
-  /**
-   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
-   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-   *             {@link #getMinX()} und {@link #getMinY()})
-   */
-  public Object getRasterSample(int... cell);
-
-  /**
-   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
-   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-   *             {@link #getMinX()} und {@link #getMinY()})
-   */
-  public short getRasterSampleAsShort(int... cell);
-
-  /**
-   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
-   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-   *             {@link #getMinX()} und {@link #getMinY()})
-   */
-  public byte getRasterSampleAsByte(int... cell);
-
-  /**
-   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
-   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-   *             {@link #getMinX()} und {@link #getMinY()})
-   */
-  public int getRasterSampleAsInt(int... cell);
-
-  /**
-   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
-   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-   *             {@link #getMinX()} und {@link #getMinY()})
-   */
-  public long getRasterSampleAsLong(int... cell);
-
-  /**
-   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
-   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-   *             {@link #getMinX()} und {@link #getMinY()})
-   */
-  public float getRasterSampleAsFloat(int... cell);
-
-  /**
-   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
-   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-   *             {@link #getMinX()} und {@link #getMinY()})
-   */
-  public double getRasterSampleAsDouble(int... cell);
-
-  /**
-   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   */
-  public Object getGridSample(double... coord);
-
-  /**
-   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   */
-  public short getGridSampleAsShort(double... coord);
-
-  /**
-   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   */
-  public byte getGridSampleAsByte(double... coord);
-
-  /**
-   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   */
-  public int getGridSampleAsInt(double... coord);
-
-  /**
-   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   */
-  public long getGridSampleAsLong(double... coord);
-
-  /**
-   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   */
-  public float getGridSampleAsFloat(double... coord);
-
-  /**
-   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   */
-  public double getGridSampleAsDouble(double... coord);
-
-  /**
-   * Konvertiert eine reale Koordinate in eine Zellennummer. Liegt der
-   * Koordinatenwert genau auf der Grenze zwischen zwei Rasterzellen, wird
-   * die naechst "groessere" Zellegewaehlt.
-   * Ausnahme bildet der Rand des Rasters. Hier wird die kleinere Zelle
-   * (also die letzte) herangezogen
-   * @param coord Georeferenz-Koordinate
-   * @param dim   Dimension, in der die Umrechnung erfolgen soll
-   * @exception UnsupportedOperationException falls eine ungueltige Dimension
-   *            angegeben wird (nur Werte 0 <= coord < {@link #RASTER_DIM} sind
-   *            zulaessig
-   */
-  public int convertRealToRaster(double coord, int dim);
-
-  /**
-   * Konvertiert eine Zellennummer in reale Koordinate. Dabei wird die
-   * Koordinate der Zellenmitte zurueckgegeben.
-   * @param cell  Rasterzellen-Koordinate
-   * @param dim   Dimension, in der die Umrechnung erfolgen soll
-   * @exception UnsupportedOperationException falls eine ungueltige Dimension
-   *            angegeben wird (nur Werte 0 <= coord < {@link #RASTER_DIM} sind
-   *            zulaessig
-   */
-  public double convertRasterToReal(int cell, int dim);
-}
+/**
+ * Dieses Interface stellt die Basis fuer ein georeferenziertes
+ * Raster dar.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public interface ReadableGrid extends LateLoadable {
+  /**
+   * Die Dimension des Rasters (2).
+   */
+  public static final int RASTER_DIM = 2;
+
+  /**
+   * Zerstoert das Raster und gibt alle Ressourcen wieder frei.
+   */
+  public void dispose();
+
+  /**
+   * Liefert die Breite des Rasters (in Zellen).
+   */
+  public int getWidth();
+
+  /**
+   * Liefert die Hoehe des Rasters (in Zellen).
+   */
+  public int getHeight();
+
+  /**
+   * Liefert den Index der ersten (Südwest) Zelle in X-Richtung.
+   */
+  public int getMinX();
+
+  /**
+   * Liefert den Index der ersten Zelle (Südwest) in Y-Richtung.
+   */
+  public int getMinY();
+
+  /**
+   * Liefert das {@link CoordinateReferenceSystem} in dem das Raster
+   * dargestellt ist.
+   */
+  public CoordinateReferenceSystem getCoordinateReferenceSystem();
+
+  /**
+   * Liefert die reale Breite des Rasters.
+   */
+  public double getRealWidth();
+
+  /**
+   * Liefert die reale Breite des Rasters.
+   */
+  public double getRealHeight();
+
+  /**
+   * Liefert die reale Breite einer Zelle.<br>
+   * Sollte <code>{@link #getRealWidth()} / {@link #getWidth()} entsprechen!
+   */
+  public double getCellWidth();
+
+  /**
+   * Liefert die reale Hoehe einer Zelle.<br>
+   * Sollte <code>{@link #getRealHeight()} / {@link #getHeight()} entsprechen!
+   */
+  public double getCellHeight();
+
+  /**
+   * Liefert die X-Koordinate (Longitude) der Georeferenz der linken unteren Ecke des Rasters (Südwest).
+   */
+  public double getX();
+
+  /**
+   * Liefert die Y-Koordinate (Latitude) der Georeferenz der linken unteren Ecke des Rasters (Südwest).
+   */
+  public double getY();
+
+  /**
+   * Liefert die Art der Daten, die im Raster gespeichert werden koennen. Diese
+   * wird durch eine der TYPE-Konstanten in {@link java.awt.image.DataBuffer}
+   * repraesentiert.
+   */
+  public int getSampleType();
+
+
+  /**
+   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
+   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+   *             {@link #getMinX()} und {@link #getMinY()})
+   */
+  public Object getRasterSample(int... cell);
+
+  /**
+   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
+   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+   *             {@link #getMinX()} und {@link #getMinY()})
+   */
+  public short getRasterSampleAsShort(int... cell);
+
+  /**
+   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
+   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+   *             {@link #getMinX()} und {@link #getMinY()})
+   */
+  public byte getRasterSampleAsByte(int... cell);
+
+  /**
+   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
+   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+   *             {@link #getMinX()} und {@link #getMinY()})
+   */
+  public int getRasterSampleAsInt(int... cell);
+
+  /**
+   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
+   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+   *             {@link #getMinX()} und {@link #getMinY()})
+   */
+  public long getRasterSampleAsLong(int... cell);
+
+  /**
+   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
+   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+   *             {@link #getMinX()} und {@link #getMinY()})
+   */
+  public float getRasterSampleAsFloat(int... cell);
+
+  /**
+   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
+   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+   *             {@link #getMinX()} und {@link #getMinY()})
+   */
+  public double getRasterSampleAsDouble(int... cell);
+
+  /**
+   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   */
+  public Object getGridSample(double... coord);
+
+  /**
+   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   */
+  public short getGridSampleAsShort(double... coord);
+
+  /**
+   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   */
+  public byte getGridSampleAsByte(double... coord);
+
+  /**
+   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   */
+  public int getGridSampleAsInt(double... coord);
+
+  /**
+   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   */
+  public long getGridSampleAsLong(double... coord);
+
+  /**
+   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   */
+  public float getGridSampleAsFloat(double... coord);
+
+  /**
+   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   */
+  public double getGridSampleAsDouble(double... coord);
+
+  /**
+   * Konvertiert eine reale Koordinate in eine Zellennummer. Liegt der
+   * Koordinatenwert genau auf der Grenze zwischen zwei Rasterzellen, wird
+   * die naechst "groessere" Zellegewaehlt.
+   * Ausnahme bildet der Rand des Rasters. Hier wird die kleinere Zelle
+   * (also die letzte) herangezogen
+   * @param coord Georeferenz-Koordinate
+   * @param dim   Dimension, in der die Umrechnung erfolgen soll
+   * @exception UnsupportedOperationException falls eine ungueltige Dimension
+   *            angegeben wird (nur Werte 0 <= coord < {@link #RASTER_DIM} sind
+   *            zulaessig
+   */
+  public int convertRealToRaster(double coord, int dim);
+
+  /**
+   * Konvertiert eine Zellennummer in reale Koordinate. Dabei wird die
+   * Koordinate der Zellenmitte zurueckgegeben.
+   * @param cell  Rasterzellen-Koordinate
+   * @param dim   Dimension, in der die Umrechnung erfolgen soll
+   * @exception UnsupportedOperationException falls eine ungueltige Dimension
+   *            angegeben wird (nur Werte 0 <= coord < {@link #RASTER_DIM} sind
+   *            zulaessig
+   */
+  public double convertRasterToReal(int cell, int dim);
+}

Modified: trunk/src/schmitzm/data/WritableGrid.java
===================================================================
--- trunk/src/schmitzm/data/WritableGrid.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/WritableGrid.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,35 +1,53 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+/**
+ * Dieses Interface stellt die Basis fuer ein georeferenziertes, schreibbares
+ * Raster dar.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public interface WritableGrid extends ReadableGrid {
+  /**
+   * Setzt einen Wert im Raster ueber Raster-Koordinaten.
+   * @param value neuer Wert
+   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+   *             {@link #getMinX()} und {@link #getMinY()})
+   */
+  public void setRasterSample(Object value, int... cell);
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.data;
-
-/**
- * Dieses Interface stellt die Basis fuer ein georeferenziertes, schreibbares
- * Raster dar.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public interface WritableGrid extends ReadableGrid {
-  /**
-   * Setzt einen Wert im Raster ueber Raster-Koordinaten.
-   * @param value neuer Wert
-   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-   *             {@link #getMinX()} und {@link #getMinY()})
-   */
-  public void setRasterSample(Object value, int... cell);
-
-  /**
-   * Setzt einen Wert im Raster ueber Geo-Koordinaten.
-   * @param value neuer Wert
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   */
-  public void setGridSample(Object value, double... coord);
-}
+  /**
+   * Setzt einen Wert im Raster ueber Geo-Koordinaten.
+   * @param value neuer Wert
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   */
+  public void setGridSample(Object value, double... coord);
+}

Modified: trunk/src/schmitzm/data/WritableGridArray.java
===================================================================
--- trunk/src/schmitzm/data/WritableGridArray.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/WritableGridArray.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,1211 +1,1229 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.data;
-
-import java.awt.geom.Rectangle2D;
-import java.awt.image.DataBuffer;
-import java.awt.image.DataBufferDouble;
-import java.awt.image.DataBufferFloat;
-import java.awt.image.DataBufferInt;
-import java.awt.image.Raster;
-import java.awt.image.RenderedImage;
-import java.io.IOException;
-import java.io.Serializable;
-
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-
-import appl.util.RasterMetaData;
-
-/**
- * Diese Klasse stellt eine Implementierung von {@link WritableGrid} dar und
- * basiert auf einem einfachen {@code float}-Array.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public abstract class WritableGridArray extends AbstractWritableGrid implements WritableGrid, Serializable {
-  /** Die Dimension des Rasters (2). */
-  public static final int RASTER_DIM = 2;
-  /** Speichert die Geo-Referenz (Latitude, Longitude, Breite, Hoehe) des
-   *  Rasters. */
-  protected transient Rectangle2D envelope;
-  /** Speichert die kleinste horizontale Raster-Koordinate. */
-  protected int minX = 0;
-  /** Speichert die kleinste vertikale Raster-Koordinate. */
-  protected int minY = 0;
-  /** Speichert die Breite des Rasters in Zellen. */
-  protected int rasterWidth = 0;
-  /** Speichert die Hoehe des Rasters in Zellen. */
-  protected int rasterHeight = 0;
-
-  /**
-   * Erzeugt ein neues Raster.
-   * @param minX Raster-Index der ersten Zelle in X-Richtung
-   * @param minY Raster-Index der ersten Zelle in Y-Richtung
-   * @param rasterWidth Breite des Rasters (in Zellen)
-   * @param rasterHeight Hoehe des Rasters (in Zellen)
-   * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
-   */
-  public WritableGridArray(int minX, int minY, int rasterWidth, int rasterHeight, Rectangle2D envelope, CoordinateReferenceSystem crs) {
-    super(crs);
-    this.minX = minX;
-    this.minY = minY;
-    this.rasterWidth  = rasterWidth;
-    this.rasterHeight = rasterHeight;
-    this.envelope = envelope;
-  }
-
-  /**
-   * Erzeugt ein neues Raster in WGS84.
-   * @param minX Raster-Index der ersten Zelle in X-Richtung
-   * @param minY Raster-Index der ersten Zelle in Y-Richtung
-   * @param rasterWidth Breite des Rasters (in Zellen)
-   * @param rasterHeight Hoehe des Rasters (in Zellen)
-   * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
-   */
-//  public WritableGridArray(int minX, int minY, int rasterWidth, int rasterHeight, Rectangle2D envelope) {
-//    this(minX, minY,rasterWidth,rasterHeight,envelope,null);
-//  }
-
-  /**
-   * Erzeugt ein neues Raster in WGS84.
-   * @param minX Raster-Index der ersten Zelle in X-Richtung
-   * @param minY Raster-Index der ersten Zelle in Y-Richtung
-   * @param rasterWidth Breite des Rasters (in Zellen)
-   * @param rasterHeight Hoehe des Rasters (in Zellen)
-   * @param lon Georeferenz (Longitude = X-Koordinate)
-   * @param lat Georeferenz (Latitude = Y-Koordinate)
-   * @param realWidth Breite des Rasters (in Metern)
-   * @param realHeight Hoehe des Rasters (in Metern)
-   */
-//  public WritableGridArray(int minX, int minY, int rasterWidth, int rasterHeight, double lon, double lat, double realWidth, double realHeight) {
-//    this( minX, minY, rasterWidth, rasterHeight, new Rectangle2D.Double(lon,lat,realWidth,realHeight) );
-//  }
-
-  /**
-   * Erzeugt ein neues Raster in WGS84.
-   * @param rasterWidth Breite des Rasters (in Zellen)
-   * @param rasterHeight Hoehe des Rasters (in Zellen)
-   * @param lon Georeferenz (Longitude = X-Koordinate)
-   * @param lat Georeferenz (Latitude = Y-Koordinate)
-   * @param realWidth Breite des Rasters (in Metern)
-   * @param realHeight Hoehe des Rasters (in Metern)
-   */
-//  public WritableGridArray(int rasterWidth, int rasterHeight, double lon, double lat, double realWidth, double realHeight) {
-//    this(0,0,rasterWidth,rasterHeight,lon,lat,realWidth,realHeight);
-//  }
-
-  /**
-   * Erzeugt ein neues Raster in WGS84.
-   * @param rasterWidth Breite des Rasters (in Zellen)
-   * @param rasterHeight Hoehe des Rasters (in Zellen)
-   * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
-   */
-//  public WritableGridArray(int rasterWidth, int rasterHeight, Rectangle2D envelope) {
-//    this(0,0,rasterWidth,rasterHeight,envelope);
-//  }
-
-  /**
-   * Erzeugt ein neues Raster.
-   * @param image Daten
-   * @param envelope Georeferenz und Ausdehnung des Rasters
-   * @param crs CoordinateReferenceSystem fuer das Raster
-   * @return Ein {@link WritableGridArray.Integer}, {@link WritableGridArray.Float} oder
-   *         {@link WritableGridArray.Double}, je nach Datentyp des {@code image}-DataBuffers
-   */
-  public static WritableGridArray create(RenderedImage image, Rectangle2D envelope, CoordinateReferenceSystem crs) {
-    return create(image.getData(),envelope,crs);
-//    int width  = image.getWidth();
-//    int height = image.getHeight();
-//    switch (image.getData().getDataBuffer().getDataType()) {
-//      case DataBuffer.TYPE_BYTE:
-//      case DataBuffer.TYPE_SHORT:
-//      case DataBuffer.TYPE_USHORT:
-//      case DataBuffer.TYPE_INT:    return new WritableGridArray.Integer(width,height,envelope,crs,image.getData());
-//      case DataBuffer.TYPE_FLOAT:  return new WritableGridArray.Float(width,height,envelope,crs,image.getData());
-//      case DataBuffer.TYPE_DOUBLE: return new WritableGridArray.Double(width,height,envelope,crs,image.getData());
-//
-//    }
-//    throw new UnsupportedOperationException("Data type of image not yet supported: "+image.getData().getDataBuffer().getDataType());
-  }
-
-  /**
-   * Erzeugt ein neues Raster in WGS84.
-   * @param image Daten
-   * @param envelope Georeferenz und Ausdehnung des Rasters
-   * @return Ein {@link WritableGridArray.Integer}, {@link WritableGridArray.Float} oder
-   *         {@link WritableGridArray.Double}, je nach Datentyp des {@code image}-DataBuffers
-   */
-  public static WritableGridArray create(RenderedImage image, Rectangle2D envelope) {
-    return create(image,envelope,null);
-  }
-
-  /**
-   * Erzeugt ein neues Raster.
-   * @param image Daten
-   * @param envelope Georeferenz und Ausdehnung des Rasters
-   * @param crs CoordinateReferenceSystem fuer das Raster
-   * @return Ein {@link WritableGridArray.Integer}, {@link WritableGridArray.Float} oder
-   *         {@link WritableGridArray.Double}, je nach Datentyp des {@code image}-DataBuffers
-   */
-  public static WritableGridArray create(Raster raster, Rectangle2D envelope, CoordinateReferenceSystem crs) {
-    int width  = raster.getWidth();
-    int height = raster.getHeight();
-    switch (raster.getDataBuffer().getDataType()) {
-      case DataBuffer.TYPE_BYTE:
-      case DataBuffer.TYPE_SHORT:
-      case DataBuffer.TYPE_USHORT:
-      case DataBuffer.TYPE_INT:    return new WritableGridArray.Integer(width,height,envelope,crs,raster);
-      case DataBuffer.TYPE_FLOAT:  return new WritableGridArray.Float(width,height,envelope,crs,raster);
-      case DataBuffer.TYPE_DOUBLE: return new WritableGridArray.Double(width,height,envelope,crs,raster);
-
-    }
-    throw new UnsupportedOperationException("Data type of image not yet supported: "+raster.getDataBuffer().getDataType());
-  }
-
-  /**
-   * Erzeugt ein neues Raster in WGS84.
-   * @param raster Daten
-   * @param envelope Georeferenz und Ausdehnung des Rasters
-   * @return Ein {@link WritableGridArray.Integer}, {@link WritableGridArray.Float} oder
-   *         {@link WritableGridArray.Double}, je nach Datentyp des {@code raster}-DataBuffers
-   */
-  public static WritableGridArray create(Raster raster, Rectangle2D envelope) {
-    return create(raster,envelope,null);
-  }
-
-  /**
-   * Creates an empty GridArray out of a {@link RasterMetaData} object.
-   * @param metaData the MetaData
-   * @param crs CoordinateReferenceSystem fuer das Raster
-   * @return A {@link WritableGridArray.Integer}, {@link WritableGridArray.Float} or
-   *         {@link WritableGridArray.Double}, depending on the Datatype
-   */
-  public static WritableGridArray createEmpty(RasterMetaData metaData, CoordinateReferenceSystem crs) {
-    switch (metaData.getDataType()) {
-      case DataBuffer.TYPE_INT:    return new WritableGridArray.Integer(metaData.getMinX(),metaData.getMinY(),metaData.getWidth(),metaData.getHeight(),metaData.getX(),metaData.getY(),metaData.getRealWidth(),metaData.getRealHeight(),crs,null);
-      case DataBuffer.TYPE_FLOAT:  return new WritableGridArray.Float(metaData.getMinX(),metaData.getMinY(),metaData.getWidth(),metaData.getHeight(),metaData.getX(),metaData.getY(),metaData.getRealWidth(),metaData.getRealHeight(),crs,null);
-      case DataBuffer.TYPE_DOUBLE: return new WritableGridArray.Double(metaData.getMinX(),metaData.getMinY(),metaData.getWidth(),metaData.getHeight(),metaData.getX(),metaData.getY(),metaData.getRealWidth(),metaData.getRealHeight(),crs,null);
-
-    }
-    throw new UnsupportedOperationException("Data type of image not yet supported!");
-  }
-
-  /**
-   * Creates an empty GridArray out of a {@link RasterMetaData} object. WGS84 is
-   * used for CRS.
-   * @param metaData the MetaData
-   * @return A {@link WritableGridArray.Integer}, {@link WritableGridArray.Float} or
-   *         {@link WritableGridArray.Double}, depending on the Datatype
-   */
-  public static WritableGridArray createEmpty(RasterMetaData metaData) {
-    return createEmpty(metaData,metaData.getCoordinateReferenceSystem());
-  }
-
-  /**
-   * Liefert eine Referenz auf den kompletten Inhalt des Rasters in Form eines
-   * {@link DataBuffer}.
-   */
-  public abstract DataBuffer getDataBuffer();
-
-  /**
-   * Liefert eine Referenz auf den kompletten Inhalt des Rasters.
-   * @return einen 1-dimensionalen Array eines Basis-Datentyps
-   */
-  public abstract Object getData();
-
-  /**
-   * Liefert eine Kopie des kompletten Inhalts des Rasters.
-   * @param data Array in den die Daten geschrieben werden (kann {@code null} sein!)
-   * @return einen 2-dimensionaler Array eines Basis-Datentyps (z.B. {@code float[height][width]})
-   */
-  public abstract Object getData(Object data);
-
-  /**
-   * Macht zur Zeit noch nichts.
-   * @todo WritableGridArray.dispose() implementieren
-   */
-  public void dispose() {
-  }
-
-  /**
-   * Liefert die X-Koordinate der Georeferenz (Longitude) der linken unteren
-   * Ecke des Rasters (Südwest).
-   */
-  public double getX() {
-    return envelope.getX();
-  }
-
-  /**
-   * Liefert die Y-Koordinate der Georeferenz (Latitude) der linken unteren
-   * Ecke des Rasters (Südwest).
-   */
-  public double getY() {
-    return envelope.getY();
-  }
-
-  /**
-   * Liefert die reale Breite des Rasters.
-   */
-  public double getRealWidth() {
-    return envelope.getWidth();
-  }
-
-  /**
-   * Liefert die reale Breite des Rasters.
-   */
-  public double getRealHeight() {
-    return envelope.getHeight();
-  }
-
-  /**
-   * Liefert die Georeferenz (Lat/Lon) und Ausdehnung des Rasters.
-   */
-  public Rectangle2D getEnvelope() {
-    return (Rectangle2D)envelope.clone();
-  }
-
-  /**
-   * Liefert die Breite des Rasters (in Zellen).
-   */
-  public int getWidth() {
-    return this.rasterWidth;
-  }
-
-  /**
-   * Liefert die Hoehe des Rasters (in Zellen).
-   */
-  public int getHeight() {
-    return this.rasterHeight;
-  }
-
-  /**
-   * Liefert den Index der ersten (Südwest) Zelle in X-Richtung.
-   */
-  public int getMinX() {
-    return this.minX;
-  }
-
-  /**
-   * Liefert den Index der ersten Zelle (Südwest) in Y-Richtung.
-   */
-  public int getMinY() {
-    return this.minY;
-  }
-
-  /** Serializes the Grid
-   * @author Dominik Appl
-   * @param s
-   * @throws IOException
-   */
-  private synchronized void writeObject( java.io.ObjectOutputStream s )
-  throws IOException
-  {
-	  //writing all attributes to the outputstream
-	  s.defaultWriteObject();
-	  //writing the transient envelope (which is not serializable)
-	  s.writeDouble(envelope.getX());
-	  s.writeDouble(envelope.getY());
-	  s.writeDouble(envelope.getHeight());
-	  s.writeDouble(envelope.getWidth());
-
-  }
-
-  /** Deserializes the Grid
-   * @author Dominik Appl
-   * @param s
-   * @throws IOException
-   */
-  private synchronized void readObject( java.io.ObjectInputStream s )
-   throws IOException, ClassNotFoundException
-   {
-	  //reading standard fields
-	  s.defaultReadObject();
-	  //reading envelope
-	  double lat = s.readDouble();
-	  double lon = s.readDouble();
-	  double realHeight = s.readDouble();
-	  double realWidth = s.readDouble();
-	  envelope = new Rectangle2D.Double(lat,lon,realWidth,realHeight);
-   }
-
-  /////////////////////////////////////////////////////////////////////////
-  ///////////////////////////   Float - Raster ////////////////////////////
-  /////////////////////////////////////////////////////////////////////////
-  public static class Float extends WritableGridArray {
-    /** Speichert zeilenweise die Daten des {@code float}-Rasters ({@code data[y*w+x])} */
-    protected float[] data = null;
-
-    /**
-     * Erzeugt ein neues {@code float}-Raster.
-     * @param minX Raster-Index der ersten Zelle in X-Richtung
-     * @param minY Raster-Index der ersten Zelle in Y-Richtung
-     * @param rasterWidth Breite des Rasters (in Zellen)
-     * @param rasterHeight Hoehe des Rasters (in Zellen)
-     * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
-     * @param crs Referenzsystem fuer das Raster
-     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss der Array
-     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
-     */
-    public Float(int minX, int minY, int rasterWidth, int rasterHeight, Rectangle2D envelope, CoordinateReferenceSystem crs, float[] data) {
-      super(minX,minY,rasterWidth,rasterHeight,envelope,crs);
-      if ( data == null )
-        data = new float[rasterHeight*rasterWidth];
-      if ( data.length < rasterHeight*rasterWidth )
-        throw new IllegalArgumentException("Array for raster content to small!");
-      this.data = data;
-    }
-
-    /**
-     * Erzeugt ein neues {@code float}-Raster.
-     * @param minX Raster-Index der ersten Zelle in X-Richtung
-     * @param minY Raster-Index der ersten Zelle in Y-Richtung
-     * @param rasterWidth Breite des Rasters (in Zellen)
-     * @param rasterHeight Hoehe des Rasters (in Zellen)
-     * @param lon Georeferenz (Longitude = X-Koordinate)
-     * @param lat Georeferenz (Latitude = Y-Koordinate)
-     * @param realWidth Breite des Rasters (in Metern)
-     * @param realHeight Hoehe des Rasters (in Metern)
-     * @param crs Referenzsystem fuer das Raster
-     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss der Array
-     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
-     */
-    public Float(int minX, int minY, int rasterWidth, int rasterHeight, double lon, double lat, double realWidth, double realHeight, CoordinateReferenceSystem crs, float[] data) {
-      this( minX, minY, rasterWidth, rasterHeight, new Rectangle2D.Double(lon,lat,realWidth,realHeight),crs, data );
-    }
-
-    /**
-     * Erzeugt ein neues leeres {@code float}-Raster.
-     * @param rasterWidth Breite des Rasters (in Zellen)
-     * @param rasterHeight Hoehe des Rasters (in Zellen)
-     * @param lon Georeferenz (Longitude = X-Koordinate)
-     * @param lat Georeferenz (Latitude = Y-Koordinate)
-     * @param realWidth Breite des Rasters (in Metern)
-     * @param realHeight Hoehe des Rasters (in Metern)
-     * @param crs Referenzsystem fuer das Raster
-     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss der Array
-     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
-     */
-    public Float(int rasterWidth, int rasterHeight, double lon, double lat, double realWidth, double realHeight, CoordinateReferenceSystem crs, float[] data) {
-      this(0,0,rasterWidth,rasterHeight,lon,lat,realWidth,realHeight,crs,data);
-    }
-
-    /**
-     * Erzeugt ein neues leeres {@code float}-Raster.
-     * @param rasterWidth Breite des Rasters (in Zellen)
-     * @param rasterHeight Hoehe des Rasters (in Zellen)
-     * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
-     * @param crs Referenzsystem fuer das Raster
-     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss der Array
-     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
-     */
-    public Float(int rasterWidth, int rasterHeight, Rectangle2D envelope, CoordinateReferenceSystem crs, float[] data) {
-      this(0,0,rasterWidth,rasterHeight,envelope,crs,data);
-    }
-
-    /**
-     * Erzeugt ein neues leeres {@code float}-Raster.
-     * @param rasterWidth Breite des Rasters (in Zellen)
-     * @param rasterHeight Hoehe des Rasters (in Zellen)
-     * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
-     * @param crs Referenzsystem fuer das Raster
-     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss der Array
-     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
-     */
-    public Float(int rasterWidth, int rasterHeight, Rectangle2D envelope, CoordinateReferenceSystem crs, float[][] data) {
-      this(0,0,rasterWidth,rasterHeight,envelope,crs,null);
-      // Daten in Array uebernehmen
-      for (int y=0; y<rasterHeight; y++)
-        for (int x=0; x<rasterWidth; x++)
-          this.data[y*rasterWidth+x] = data[x][y];
-    }
-
-    /**
-     * Erzeugt ein neues leeres {@code float}-Raster.
-     * @param rasterWidth Breite des Rasters (in Zellen)
-     * @param rasterHeight Hoehe des Rasters (in Zellen)
-     * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
-     * @param crs Referenzsystem fuer das Raster
-     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss das Raster
-     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
-     */
-    public Float(int rasterWidth, int rasterHeight, Rectangle2D envelope, CoordinateReferenceSystem crs, Raster data) {
-      this(0,0,rasterWidth,rasterHeight,envelope,crs,null);
-      // Daten in Array uebernehmen
-      data.getPixels(0,0,rasterWidth,rasterHeight,this.data);
-    }
-
-    /**
-     * Liefert eine Referenz auf den kompletten Inhalt des Raster.
-     * @return {@code float[height*width]}-Array.
-     */
-    public float[] getData() {
-      return this.data;
-    }
-
-    /**
-     * Liefert eine Referenz auf den kompletten Inhalt des Rasters in Form eines
-     * {@link DataBuffer}.
-     */
-    public DataBufferFloat getDataBuffer() {
-      return new DataBufferFloat(data,data.length);
-    }
-
-    /**
-     * Liefert eine Kopie des kompletten Inhalts des Rasters.
-     * @param data Array in den die Daten geschrieben werden (kann {@code null} sein!)
-     * @return einen {@code float[height][width]}-Array.
-     */
-    public float[][] getData(Object data) {
-      return getData((float[][])data);
-    }
-    /**
-     * Liefert eine Kopie des kompletten Inhalts des Rasters.
-     * @param data Array in den die Daten geschrieben werden (kann {@code null} sein!)
-     * @return {@code float[height][width]}-Array.
-     */
-    public float[][] getData(float[][] data) {
-      if ( data == null )
-        data = new float[rasterHeight][rasterWidth];
-      for (int y=0; y<rasterHeight; y++)
-        for (int x=0; x<rasterWidth; x++)
-          data[y][x] = this.data[y*rasterWidth+x];
-      return data;
-    }
-
-    /**
-     * Liefert eine Kopie des kompletten Inhalts des Rasters. Die {@code float}-Werte
-     * des Rasters werden einfach zu {@code int} gecastet.
-     * @param data Array in den die Daten geschrieben werden (kann {@code null} sein!)
-     * @return {@code int[height][width]}-Array.
-     */
-    public int[][] getData(int[][] data) {
-      if ( data == null )
-        data = new int[rasterHeight][rasterWidth];
-      for (int y=0; y<rasterHeight; y++)
-        for (int x=0; x<rasterWidth; x++)
-          data[y][x] = (int)this.data[y*rasterWidth+x];
-      return data;
-    }
-
-    /**
-     * Liefert eine Kopie des kompletten Inhalts des Rasters. Die {@code float}-Werte
-     * des Rasters werden einfach zu {@code double} gecastet.
-     * @param data Array in den die Daten geschrieben werden (kann {@code null} sein!)
-     * @return {@code double[height][width]}-Array.
-     */
-    public double[][] getData(double[][] data) {
-      if ( data == null )
-        data = new double[rasterHeight][rasterWidth];
-      for (int y=0; y<rasterHeight; y++)
-        for (int x=0; x<rasterWidth; x++)
-          data[y][x] = this.data[y*rasterWidth+x];
-      return data;
-    }
-
-    /**
-     * Liefert die Art der Daten, die im Raster gespeichert werden koennen. Diese
-     * wird durch eine der TYPE-Konstanten in {@link DataBuffer}
-     * repraesentiert.
-     * @return immer {@link DataBuffer#TYPE_FLOAT DataBuffer.TYPE_FLOAT}
-     */
-    public int getSampleType() {
-      return DataBuffer.TYPE_FLOAT;
-    }
-
-    /**
-     * Setzt einen Wert im Raster ueber Raster-Koordinaten.
-     * @param value neuer Wert
-     * @param cell  2D-Raster-Koordinate (Zellenindizes, beginnend bei
-     *              {@link #getMinX()} und {@link #getMinY()})
-     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
-     *            Koordinaten angegeben werden
-     */
-    public void setRasterSample(Object value, int ...cell) {
-      if (cell.length < RASTER_DIM)
-        throw new UnsupportedOperationException(RASTER_DIM +
-                                                " Coordinates expected");
-      if (value == null)
-        throw new UnsupportedOperationException(getClass().getSimpleName() +
-                                                " can not store null-Objects");
-      if (! (value instanceof java.lang.Number))
-        throw new UnsupportedOperationException(getClass().getSimpleName() +
-                                                " only can not store "+value.getClass().getSimpleName()+"-Objects");
-
-      int x = cell[0] - minX;
-      int y = cell[1] - minY;
-      data[y*rasterWidth+x] = ((Number)value).floatValue();
-    }
-
-    /**
-     * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
-     * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-     *             {@link #getMinX()} und {@link #getMinY()})
-     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
-     *            Koordinaten angegeben werden
-     */
-    public java.lang.Float getRasterSample(int ...cell) {
-      if (cell.length < RASTER_DIM)
-        throw new UnsupportedOperationException(RASTER_DIM + " Coordinates expected");
-      int x = cell[0] - minX;
-      int y = cell[1] - minY;
-      return data[y*rasterWidth+x];
-    }
-
-    /**
-     * Liefert einen Wert des Rasters ueber Raster-Koordinaten. Greift direkt
-     * auf den Daten-Array zu und nutzt nicht die generischen Methoden der
-     * Oberklasse.
-     * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-     *             {@link #getMinX()} und {@link #getMinY()})
-     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
-     *            Koordinaten angegeben werden
-     */
-    public float getRasterSampleAsFloat(int... cell) {
-      int x = cell[0] - minX;
-      int y = cell[1] - minY;
-      return data[y*rasterWidth+x];
-    }
-
-    /**
-     * Setzt einen Wert des Rasters ueber Raster-Koordinaten. Greift direkt
-     * auf den Daten-Array zu und nutzt nicht die generischen Methoden der
-     * Oberklasse.
-     * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-     *             {@link #getMinX()} und {@link #getMinY()})
-     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
-     *            Koordinaten angegeben werden
-     */
-    public void setRasterSample(float value, int... cell) {
-      if ( cell.length < RASTER_DIM )
-        throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
-      int x = cell[0] - minX;
-      int y = cell[1] - minY;
-      data[y*rasterWidth+x] = value;
-    }
-
-    /**
-     * Liefert einen Wert des Rasters ueber Geo-Koordinaten. Greift direkt
-     * auf den Daten-Array zu und nutzt nicht die generischen Methoden der
-     * Oberklasse.
-     * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
-     *            Koordinaten angegeben werden
-     */
-    public float getGridSampleAsFloat(double... coord){
-      if ( coord.length < RASTER_DIM )
-        throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
-      // Koordinaten umrechnen in Zellen-Index
-      int cellX = convertRealToRaster(coord[0],0);
-      int cellY = convertRealToRaster(coord[1],1);
-      return data[cellY*rasterWidth + cellX];
-    }
-
-    /**
-     * Setzt einen Wert des Rasters ueber Geo-Koordinaten. Liegt der
-     * Koordinatenwert genau auf der Grenze zwischen zwei Rasterzellen, wird die
-     * naechst groessere Zelle gewaehlt (ausser die Grenze entspricht dem Raster-Rand!).
-     * Greift direkt auf den Daten-Array zu und nutzt nicht die generischen Methoden der
-     * Oberklasse.
-     * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
-     *            Koordinaten angegeben werden
-     */
-    public void setGridSample(float value, int... coord) {
-      if ( coord.length < RASTER_DIM )
-        throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
-      // Koordinaten umrechnen in Zellen-Index
-      int cellX = convertRealToRaster(coord[0],0);
-      int cellY = convertRealToRaster(coord[1],1);
-      data[cellY*rasterWidth+cellX] = value;
-    }
-  }
-
-  /////////////////////////////////////////////////////////////////////////
-  ///////////////////////////   Double - Raster ////////////////////////////
-  /////////////////////////////////////////////////////////////////////////
-  public static class Double extends WritableGridArray {
-    /** Speichert zeilenweise die Daten des {@code double}-Rasters ({@code data[y*w+x])} */
-    protected double[] data = null;
-
-    /**
-     * Erzeugt ein neues {@code double}-Raster.
-     * @param minX Raster-Index der ersten Zelle in X-Richtung
-     * @param minY Raster-Index der ersten Zelle in Y-Richtung
-     * @param rasterWidth Breite des Rasters (in Zellen)
-     * @param rasterHeight Hoehe des Rasters (in Zellen)
-     * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
-     * @param crs Referenzsystem fuer das Raster
-     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss der Array
-     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
-     */
-    public Double(int minX, int minY, int rasterWidth, int rasterHeight, Rectangle2D envelope, CoordinateReferenceSystem crs, double[] data) {
-      super(minX,minY,rasterWidth,rasterHeight,envelope,crs);
-      if ( data == null )
-        data = new double[rasterHeight*rasterWidth];
-      if ( data.length < rasterHeight*rasterWidth )
-        throw new IllegalArgumentException("Array for raster content to small!");
-      this.data = data;
-    }
-
-    /**
-     * Erzeugt ein neues {@code double}-Raster.
-     * @param minX Raster-Index der ersten Zelle in X-Richtung
-     * @param minY Raster-Index der ersten Zelle in Y-Richtung
-     * @param rasterWidth Breite des Rasters (in Zellen)
-     * @param rasterHeight Hoehe des Rasters (in Zellen)
-     * @param lon Georeferenz (Longitude = X-Koordinate)
-     * @param lat Georeferenz (Latitude = Y-Koordinate)
-     * @param realWidth Breite des Rasters (in Metern)
-     * @param realHeight Hoehe des Rasters (in Metern)
-     * @param crs Referenzsystem fuer das Raster
-     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss der Array
-     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
-     */
-    public Double(int minX, int minY, int rasterWidth, int rasterHeight, double lon, double lat, double realWidth, double realHeight, CoordinateReferenceSystem crs, double[] data) {
-      this( minX, minY, rasterWidth, rasterHeight, new Rectangle2D.Double(lon,lat,realWidth,realHeight), crs, data );
-    }
-
-    /**
-     * Erzeugt ein neues leeres {@code double}-Raster.
-     * @param rasterWidth Breite des Rasters (in Zellen)
-     * @param rasterHeight Hoehe des Rasters (in Zellen)
-     * @param lon Georeferenz (Longitude = X-Koordinate)
-     * @param lat Georeferenz (Latitude = Y-Koordinate)
-     * @param realWidth Breite des Rasters (in Metern)
-     * @param realHeight Hoehe des Rasters (in Metern)
-     * @param crs Referenzsystem fuer das Raster
-     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss der Array
-     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
-     */
-    public Double(int rasterWidth, int rasterHeight, double lon, double lat, double realWidth, double realHeight, CoordinateReferenceSystem crs, double[] data) {
-      this(0,0,rasterWidth,rasterHeight,lon,lat,realWidth,realHeight,crs,data);
-    }
-
-    /**
-     * Erzeugt ein neues leeres {@code double}-Raster.
-     * @param rasterWidth Breite des Rasters (in Zellen)
-     * @param rasterHeight Hoehe des Rasters (in Zellen)
-     * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
-     * @param crs Referenzsystem fuer das Raster
-     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss der Array
-     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
-     */
-    public Double(int rasterWidth, int rasterHeight, Rectangle2D envelope, CoordinateReferenceSystem crs, double[] data) {
-      this(0,0,rasterWidth,rasterHeight,envelope,crs,data);
-    }
-
-    /**
-     * Erzeugt ein neues leeres {@code double}-Raster.
-     * @param rasterWidth Breite des Rasters (in Zellen)
-     * @param rasterHeight Hoehe des Rasters (in Zellen)
-     * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
-     * @param crs Referenzsystem fuer das Raster
-     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss der Array
-     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
-     */
-    public Double(int rasterWidth, int rasterHeight, Rectangle2D envelope, CoordinateReferenceSystem crs, double[][] data) {
-      this(0,0,rasterWidth,rasterHeight,envelope,crs,null);
-      // Daten in Array uebernehmen
-      for (int y=0; y<rasterHeight; y++)
-        for (int x=0; x<rasterWidth; x++)
-          this.data[y*rasterWidth+x] = data[x][y];
-    }
-
-    /**
-     * Erzeugt ein neues leeres {@code double}-Raster.
-     * @param rasterWidth Breite des Rasters (in Zellen)
-     * @param rasterHeight Hoehe des Rasters (in Zellen)
-     * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
-     * @param crs Referenzsystem fuer das Raster
-     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss das Raster
-     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
-     */
-    public Double(int rasterWidth, int rasterHeight, Rectangle2D envelope, CoordinateReferenceSystem crs, Raster data) {
-      this(0,0,rasterWidth,rasterHeight,envelope,crs,null);
-      // Daten in Array uebernehmen
-      data.getPixels(0,0,rasterWidth,rasterHeight,this.data);
-    }
-
-    /**
-     * Liefert eine Referenz auf den kompletten Inhalt des Raster.
-     * @return {@code double[height*width]}-Array.
-     */
-    public double[] getData() {
-      return this.data;
-    }
-
-    /**
-     * Liefert eine Referenz auf den kompletten Inhalt des Rasters in Form eines
-     * {@link DataBuffer}.
-     */
-    public DataBufferDouble getDataBuffer() {
-      return new DataBufferDouble(data,data.length);
-    }
-
-    /**
-     * Liefert eine Kopie des kompletten Inhalts des Rasters.
-     * @param data Array in den die Daten geschrieben werden (kann {@code null} sein!)
-     * @return einen {@code double[height][width]}-Array.
-     */
-    public double[][] getData(Object data) {
-      return getData((double[][])data);
-    }
-    /**
-     * Liefert eine Kopie des kompletten Inhalts des Rasters.
-     * @param data Array in den die Daten geschrieben werden (kann {@code null} sein!)
-     * @return {@code double[height][width]}-Array.
-     */
-    public double[][] getData(double[][] data) {
-      if ( data == null )
-        data = new double[rasterHeight][rasterWidth];
-      for (int y=0; y<rasterHeight; y++)
-        for (int x=0; x<rasterWidth; x++)
-          data[y][x] = this.data[y*rasterWidth+x];
-      return data;
-    }
-
-    /**
-     * Liefert eine Kopie des kompletten Inhalts des Rasters. Die {@code double}-Werte
-     * des Rasters werden einfach zu {@code float} gecastet.
-     * @param data Array in den die Daten geschrieben werden (kann {@code null} sein!)
-     * @return {@code float[height][width]}-Array.
-     */
-    public float[][] getData(float[][] data) {
-      if ( data == null )
-        data = new float[rasterHeight][rasterWidth];
-      for (int y=0; y<rasterHeight; y++)
-        for (int x=0; x<rasterWidth; x++)
-          data[y][x] = (float)this.data[y*rasterWidth+x];
-      return data;
-    }
-
-    /**
-     * Liefert eine Kopie des kompletten Inhalts des Rasters. Die {@code double}-Werte
-     * des Rasters werden einfach zu {@code int} gecastet.
-     * @param data Array in den die Daten geschrieben werden (kann {@code null} sein!)
-     * @return {@code int[height][width]}-Array.
-     */
-    public int[][] getData(int[][] data) {
-      if ( data == null )
-        data = new int[rasterHeight][rasterWidth];
-      for (int y=0; y<rasterHeight; y++)
-        for (int x=0; x<rasterWidth; x++)
-          data[y][x] = (int)this.data[y*rasterWidth+x];
-      return data;
-    }
-
-    /**
-     * Liefert die Art der Daten, die im Raster gespeichert werden koennen. Diese
-     * wird durch eine der TYPE-Konstanten in {@link DataBuffer}
-     * repraesentiert.
-     * @return immer {@link DataBuffer#TYPE_DOUBLE DataBuffer.TYPE_DOUBLE}
-     */
-    public int getSampleType() {
-      return DataBuffer.TYPE_DOUBLE;
-    }
-
-    /**
-     * Setzt einen Wert im Raster ueber Raster-Koordinaten.
-     * @param value neuer Wert
-     * @param cell  2D-Raster-Koordinate (Zellenindizes, beginnend bei
-     *              {@link #getMinX()} und {@link #getMinY()})
-     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
-     *            Koordinaten angegeben werden
-     */
-    public void setRasterSample(Object value, int ...cell) {
-      if (cell.length < RASTER_DIM)
-        throw new UnsupportedOperationException(RASTER_DIM + " Coordinates expected");
-      if (value == null)
-        throw new UnsupportedOperationException(getClass().getSimpleName() +
-                                                " can not store null-Objects");
-      if (! (value instanceof java.lang.Number))
-        throw new UnsupportedOperationException(getClass().getSimpleName() +
-                                                " only can not store "+value.getClass().getSimpleName()+"-Objects");
-      int x = cell[0] - minX;
-      int y = cell[1] - minY;
-      data[y*rasterWidth+x] = ((java.lang.Number)value).doubleValue();
-    }
-
-    /**
-     * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
-     * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-     *             {@link #getMinX()} und {@link #getMinY()})
-     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
-     *            Koordinaten angegeben werden
-     */
-    public java.lang.Double getRasterSample(int ...cell) {
-      if (cell.length < RASTER_DIM)
-        throw new UnsupportedOperationException(RASTER_DIM + " Coordinates expected");
-      int x = cell[0] - minX;
-      int y = cell[1] - minY;
-      return data[y*rasterWidth+x];
-    }
-
-    /**
-     * Liefert einen Wert des Rasters ueber Raster-Koordinaten. Greift direkt
-     * auf den Daten-Array zu und nutzt nicht die generischen Methoden der
-     * Oberklasse.
-     * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-     *             {@link #getMinX()} und {@link #getMinY()})
-     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
-     *            Koordinaten angegeben werden
-     */
-    public double getRasterSampleAsDouble(int... cell) {
-      int x = cell[0] - minX;
-      int y = cell[1] - minY;
-      return data[y*rasterWidth+x];
-    }
-
-    /**
-     * Setzt einen Wert des Rasters ueber Raster-Koordinaten. Greift direkt
-     * auf den Daten-Array zu und nutzt nicht die generischen Methoden der
-     * Oberklasse.
-     * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-     *             {@link #getMinX()} und {@link #getMinY()})
-     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
-     *            Koordinaten angegeben werden
-     */
-    public void setRasterSample(double value, int... cell) {
-      if ( cell.length < RASTER_DIM )
-        throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
-      int x = cell[0] - minX;
-      int y = cell[1] - minY;
-      data[y*rasterWidth+x] = value;
-    }
-
-    /**
-     * Liefert einen Wert des Rasters ueber Geo-Koordinaten. Greift direkt
-     * auf den Daten-Array zu und nutzt nicht die generischen Methoden der
-     * Oberklasse.
-     * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
-     *            Koordinaten angegeben werden
-     */
-    public double getGridSampleAsDouble(double... coord){
-      if ( coord.length < RASTER_DIM )
-        throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
-      // Koordinaten umrechnen in Zellen-Index
-      int cellX = convertRealToRaster(coord[0],0);
-      int cellY = convertRealToRaster(coord[1],1);
-      return data[cellY*rasterWidth + cellX];
-    }
-
-    /**
-     * Setzt einen Wert des Rasters ueber Geo-Koordinaten. Liegt der
-     * Koordinatenwert genau auf der Grenze zwischen zwei Rasterzellen, wird die
-     * naechst groessere Zelle gewaehlt (ausser die Grenze entspricht dem Raster-Rand!).
-     * Greift direkt auf den Daten-Array zu und nutzt nicht die generischen Methoden der
-     * Oberklasse.
-     * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
-     *            Koordinaten angegeben werden
-     */
-    public void setGridSample(double value, int... coord) {
-      if ( coord.length < RASTER_DIM )
-        throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
-      // Koordinaten umrechnen in Zellen-Index
-      int cellX = convertRealToRaster(coord[0],0);
-      int cellY = convertRealToRaster(coord[1],1);
-      data[cellY*rasterWidth+cellX] = value;
-    }
-  }
-
-  /////////////////////////////////////////////////////////////////////////
-  ///////////////////////////   Integer - Raster ////////////////////////////
-  /////////////////////////////////////////////////////////////////////////
-  public static class Integer extends WritableGridArray {
-    /** Speichert zeilenweise die Daten des {@code int}-Rasters ({@code data[y*w+x])} */
-    protected int[] data = null;
-
-    /**
-     * Erzeugt ein neues {@code int}-Raster.
-     * @param minX Raster-Index der ersten Zelle in X-Richtung
-     * @param minY Raster-Index der ersten Zelle in Y-Richtung
-     * @param rasterWidth Breite des Rasters (in Zellen)
-     * @param rasterHeight Hoehe des Rasters (in Zellen)
-     * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
-     * @param crs Referenzsystem fuer das Raster
-     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss der Array
-     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
-     */
-    public Integer(int minX, int minY, int rasterWidth, int rasterHeight, Rectangle2D envelope, CoordinateReferenceSystem crs, int[] data) {
-      super(minX,minY,rasterWidth,rasterHeight,envelope,crs);
-      if ( data == null )
-        data = new int[rasterHeight*rasterWidth];
-      if ( data.length < rasterHeight*rasterWidth )
-        throw new IllegalArgumentException("Array for raster content to small!");
-      this.data = data;
-    }
-
-    /**
-     * Erzeugt ein neues {@code int}-Raster.
-     * @param minX Raster-Index der ersten Zelle in X-Richtung
-     * @param minY Raster-Index der ersten Zelle in Y-Richtung
-     * @param rasterWidth Breite des Rasters (in Zellen)
-     * @param rasterHeight Hoehe des Rasters (in Zellen)
-     * @param lon Georeferenz (Longitude = X-Koordinate)
-     * @param lat Georeferenz (Latitude = Y-Koordinate)
-     * @param realWidth Breite des Rasters (in Metern)
-     * @param realHeight Hoehe des Rasters (in Metern)
-     * @param crs Referenzsystem fuer das Raster
-     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss der Array
-     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
-     */
-    public Integer(int minX, int minY, int rasterWidth, int rasterHeight, double lon, double lat, double realWidth, double realHeight, CoordinateReferenceSystem crs, int[] data) {
-      this( minX, minY, rasterWidth, rasterHeight, new Rectangle2D.Double(lon,lat,realWidth,realHeight),crs , data );
-    }
-
-    /**
-     * Erzeugt ein neues leeres {@code int}-Raster.
-     * @param rasterWidth Breite des Rasters (in Zellen)
-     * @param rasterHeight Hoehe des Rasters (in Zellen)
-     * @param lon Georeferenz (Longitude = X-Koordinate)
-     * @param lat Georeferenz (Latitude = Y-Koordinate)
-     * @param realWidth Breite des Rasters (in Metern)
-     * @param realHeight Hoehe des Rasters (in Metern)
-     * @param crs Referenzsystem fuer das Raster
-     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss der Array
-     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
-     */
-    public Integer(int rasterWidth, int rasterHeight, double lon, double lat, double realWidth, double realHeight, CoordinateReferenceSystem crs, int[] data) {
-      this(0,0,rasterWidth,rasterHeight,lon,lat,realWidth,realHeight,crs,data);
-    }
-
-    /**
-     * Erzeugt ein neues leeres {@code int}-Raster.
-     * @param rasterWidth Breite des Rasters (in Zellen)
-     * @param rasterHeight Hoehe des Rasters (in Zellen)
-     * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
-     * @param crs Referenzsystem fuer das Raster
-     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss der Array
-     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
-     */
-    public Integer(int rasterWidth, int rasterHeight, Rectangle2D envelope, CoordinateReferenceSystem crs, int[] data) {
-      this(0,0,rasterWidth,rasterHeight,envelope,crs,data);
-    }
-
-    /**
-     * Erzeugt ein neues leeres {@code int}-Raster.
-     * @param rasterWidth Breite des Rasters (in Zellen)
-     * @param rasterHeight Hoehe des Rasters (in Zellen)
-     * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
-     * @param crs Referenzsystem fuer das Raster
-     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss der Array
-     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
-     */
-    public Integer(int rasterWidth, int rasterHeight, Rectangle2D envelope, CoordinateReferenceSystem crs, int[][] data) {
-      this(0,0,rasterWidth,rasterHeight,envelope,crs,null);
-      // Daten in Array uebernehmen
-      for (int y=0; y<rasterHeight; y++)
-        for (int x=0; x<rasterWidth; x++)
-          this.data[y*rasterWidth+x] = data[x][y];
-    }
-
-    /**
-     * Erzeugt ein neues leeres {@code int}-Raster.
-     * @param rasterWidth Breite des Rasters (in Zellen)
-     * @param rasterHeight Hoehe des Rasters (in Zellen)
-     * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
-     * @param crs Referenzsystem fuer das Raster
-     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss das Raster
-     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
-     */
-    public Integer(int rasterWidth, int rasterHeight, Rectangle2D envelope, CoordinateReferenceSystem crs, Raster data) {
-      this(0,0,rasterWidth,rasterHeight,envelope,crs,null);
-      // Daten in Array uebernehmen
-      data.getPixels(0,0,rasterWidth,rasterHeight,this.data);
-    }
-
-    /**
-     * Liefert eine Referenz auf den kompletten Inhalt des Raster.
-     * @return {@code int[height*width]}-Array.
-     */
-    public int[] getData() {
-      return this.data;
-    }
-
-    /**
-     * Liefert eine Referenz auf den kompletten Inhalt des Rasters in Form eines
-     * {@link DataBuffer}.
-     */
-    public DataBufferInt getDataBuffer() {
-      return new DataBufferInt(data,data.length);
-    }
-
-    /**
-     * Liefert eine Kopie des kompletten Inhalts des Rasters.
-     * @param data Array in den die Daten geschrieben werden (kann {@code null} sein!)
-     * @return einen {@code int[height][width]}-Array.
-     */
-    public int[][] getData(Object data) {
-      return getData((int[][])data);
-    }
-    /**
-     * Liefert eine Kopie des kompletten Inhalts des Rasters.
-     * @param data Array in den die Daten geschrieben werden (kann {@code null} sein!)
-     * @return {@code int[height][width]}-Array.
-     */
-    public int[][] getData(int[][] data) {
-      if ( data == null )
-        data = new int[rasterHeight][rasterWidth];
-      for (int y=0; y<rasterHeight; y++)
-        for (int x=0; x<rasterWidth; x++)
-          data[y][x] = this.data[y*rasterWidth+x];
-      return data;
-    }
-
-    /**
-     * Liefert eine Kopie des kompletten Inhalts des Rasters. Die {@code int}-Werte
-     * des Rasters werden einfach zu {@code float} gecastet.
-     * @param data Array in den die Daten geschrieben werden (kann {@code null} sein!)
-     * @return {@code float[height][width]}-Array.
-     */
-    public float[][] getData(float[][] data) {
-      if ( data == null )
-        data = new float[rasterHeight][rasterWidth];
-      for (int y=0; y<rasterHeight; y++)
-        for (int x=0; x<rasterWidth; x++)
-          data[y][x] = this.data[y*rasterWidth+x];
-      return data;
-    }
-
-    /**
-     * Liefert eine Kopie des kompletten Inhalts des Rasters. Die {@code int}-Werte
-     * des Rasters werden einfach zu {@code double} gecastet.
-     * @param data Array in den die Daten geschrieben werden (kann {@code null} sein!)
-     * @return {@code double[height][width]}-Array.
-     */
-    public double[][] getData(double[][] data) {
-      if ( data == null )
-        data = new double[rasterHeight][rasterWidth];
-      for (int y=0; y<rasterHeight; y++)
-        for (int x=0; x<rasterWidth; x++)
-          data[y][x] = this.data[y*rasterWidth+x];
-      return data;
-    }
-
-    /**
-     * Liefert die Art der Daten, die im Raster gespeichert werden koennen. Diese
-     * wird durch eine der TYPE-Konstanten in {@link DataBuffer}
-     * repraesentiert.
-     * @return immer {@link DataBuffer#TYPE_INT DataBuffer.TYPE_INT}
-     */
-    public int getSampleType() {
-      return DataBuffer.TYPE_INT;
-    }
-
-    /**
-     * Setzt einen Wert im Raster ueber Raster-Koordinaten.
-     * @param value neuer Wert
-     * @param cell  2D-Raster-Koordinate (Zellenindizes, beginnend bei
-     *              {@link #getMinX()} und {@link #getMinY()})
-     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
-     *            Koordinaten angegeben werden
-     */
-    public void setRasterSample(Object value, int ...cell) {
-      if (cell.length < RASTER_DIM)
-        throw new UnsupportedOperationException(RASTER_DIM + " Coordinates expected");
-      if (value == null)
-        throw new UnsupportedOperationException(getClass().getSimpleName() +
-                                                " can not store null-Objects");
-      if (! (value instanceof java.lang.Number))
-        throw new UnsupportedOperationException(getClass().getSimpleName() +
-                                                " only can not store "+value.getClass().getSimpleName()+"-Objects");
-      int x = cell[0] - minX;
-      int y = cell[1] - minY;
-      data[y*rasterWidth+x] = ((java.lang.Number)value).intValue();
-    }
-
-    /**
-     * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
-     * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-     *             {@link #getMinX()} und {@link #getMinY()})
-     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
-     *            Koordinaten angegeben werden
-     */
-    public java.lang.Integer getRasterSample(int ...cell) {
-      if (cell.length < RASTER_DIM)
-        throw new UnsupportedOperationException(RASTER_DIM + " Coordinates expected");
-      int x = cell[0] - minX;
-      int y = cell[1] - minY;
-      return data[y*rasterWidth+x];
-    }
-
-    /**
-     * Liefert einen Wert des Rasters ueber Raster-Koordinaten. Greift direkt
-     * auf den Daten-Array zu und nutzt nicht die generischen Methoden der
-     * Oberklasse.
-     * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-     *             {@link #getMinX()} und {@link #getMinY()})
-     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
-     *            Koordinaten angegeben werden
-     */
-    public int getRasterSampleAsInt(int... cell) {
-      int x = cell[0] - minX;
-      int y = cell[1] - minY;
-      return data[y*rasterWidth+x];
-    }
-
-    /**
-     * Setzt einen Wert des Rasters ueber Raster-Koordinaten. Greift direkt
-     * auf den Daten-Array zu und nutzt nicht die generischen Methoden der
-     * Oberklasse.
-     * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-     *             {@link #getMinX()} und {@link #getMinY()})
-     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
-     *            Koordinaten angegeben werden
-     */
-    public void setRasterSample(int value, int... cell) {
-      if ( cell.length < RASTER_DIM )
-        throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
-      int x = cell[0] - minX;
-      int y = cell[1] - minY;
-      data[y*rasterWidth+x] = value;
-    }
-
-    /**
-     * Liefert einen Wert des Rasters ueber Geo-Koordinaten. Greift direkt
-     * auf den Daten-Array zu und nutzt nicht die generischen Methoden der
-     * Oberklasse.
-     * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
-     *            Koordinaten angegeben werden
-     */
-    public int getGridSampleAsInt(double... coord){
-      if ( coord.length < RASTER_DIM )
-        throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
-      // Koordinaten umrechnen in Zellen-Index
-      int cellX = convertRealToRaster(coord[0],0);
-      int cellY = convertRealToRaster(coord[1],1);
-      return data[cellY*rasterWidth + cellX];
-    }
-
-    /**
-     * Setzt einen Wert des Rasters ueber Geo-Koordinaten. Liegt der
-     * Koordinatenwert genau auf der Grenze zwischen zwei Rasterzellen, wird die
-     * naechst groessere Zelle gewaehlt (ausser die Grenze entspricht dem Raster-Rand!).
-     * Greift direkt auf den Daten-Array zu und nutzt nicht die generischen Methoden der
-     * Oberklasse.
-     * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
-     *            Koordinaten angegeben werden
-     */
-    public void setGridSample(int value, int... coord) {
-      if ( coord.length < RASTER_DIM )
-        throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
-      // Koordinaten umrechnen in Zellen-Index
-      int cellX = convertRealToRaster(coord[0],0);
-      int cellY = convertRealToRaster(coord[1],1);
-      data[cellY*rasterWidth+cellX] = value;
-    }
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data;
+
+import java.awt.geom.Rectangle2D;
+import java.awt.image.DataBuffer;
+import java.awt.image.DataBufferDouble;
+import java.awt.image.DataBufferFloat;
+import java.awt.image.DataBufferInt;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.io.IOException;
+import java.io.Serializable;
+
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+
+import appl.util.RasterMetaData;
+
+/**
+ * Diese Klasse stellt eine Implementierung von {@link WritableGrid} dar und
+ * basiert auf einem einfachen {@code float}-Array.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public abstract class WritableGridArray extends AbstractWritableGrid implements WritableGrid, Serializable {
+  /** Die Dimension des Rasters (2). */
+  public static final int RASTER_DIM = 2;
+  /** Speichert die Geo-Referenz (Latitude, Longitude, Breite, Hoehe) des
+   *  Rasters. */
+  protected transient Rectangle2D envelope;
+  /** Speichert die kleinste horizontale Raster-Koordinate. */
+  protected int minX = 0;
+  /** Speichert die kleinste vertikale Raster-Koordinate. */
+  protected int minY = 0;
+  /** Speichert die Breite des Rasters in Zellen. */
+  protected int rasterWidth = 0;
+  /** Speichert die Hoehe des Rasters in Zellen. */
+  protected int rasterHeight = 0;
+
+  /**
+   * Erzeugt ein neues Raster.
+   * @param minX Raster-Index der ersten Zelle in X-Richtung
+   * @param minY Raster-Index der ersten Zelle in Y-Richtung
+   * @param rasterWidth Breite des Rasters (in Zellen)
+   * @param rasterHeight Hoehe des Rasters (in Zellen)
+   * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
+   */
+  public WritableGridArray(int minX, int minY, int rasterWidth, int rasterHeight, Rectangle2D envelope, CoordinateReferenceSystem crs) {
+    super(crs);
+    this.minX = minX;
+    this.minY = minY;
+    this.rasterWidth  = rasterWidth;
+    this.rasterHeight = rasterHeight;
+    this.envelope = envelope;
+  }
+
+  /**
+   * Erzeugt ein neues Raster in WGS84.
+   * @param minX Raster-Index der ersten Zelle in X-Richtung
+   * @param minY Raster-Index der ersten Zelle in Y-Richtung
+   * @param rasterWidth Breite des Rasters (in Zellen)
+   * @param rasterHeight Hoehe des Rasters (in Zellen)
+   * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
+   */
+//  public WritableGridArray(int minX, int minY, int rasterWidth, int rasterHeight, Rectangle2D envelope) {
+//    this(minX, minY,rasterWidth,rasterHeight,envelope,null);
+//  }
+
+  /**
+   * Erzeugt ein neues Raster in WGS84.
+   * @param minX Raster-Index der ersten Zelle in X-Richtung
+   * @param minY Raster-Index der ersten Zelle in Y-Richtung
+   * @param rasterWidth Breite des Rasters (in Zellen)
+   * @param rasterHeight Hoehe des Rasters (in Zellen)
+   * @param lon Georeferenz (Longitude = X-Koordinate)
+   * @param lat Georeferenz (Latitude = Y-Koordinate)
+   * @param realWidth Breite des Rasters (in Metern)
+   * @param realHeight Hoehe des Rasters (in Metern)
+   */
+//  public WritableGridArray(int minX, int minY, int rasterWidth, int rasterHeight, double lon, double lat, double realWidth, double realHeight) {
+//    this( minX, minY, rasterWidth, rasterHeight, new Rectangle2D.Double(lon,lat,realWidth,realHeight) );
+//  }
+
+  /**
+   * Erzeugt ein neues Raster in WGS84.
+   * @param rasterWidth Breite des Rasters (in Zellen)
+   * @param rasterHeight Hoehe des Rasters (in Zellen)
+   * @param lon Georeferenz (Longitude = X-Koordinate)
+   * @param lat Georeferenz (Latitude = Y-Koordinate)
+   * @param realWidth Breite des Rasters (in Metern)
+   * @param realHeight Hoehe des Rasters (in Metern)
+   */
+//  public WritableGridArray(int rasterWidth, int rasterHeight, double lon, double lat, double realWidth, double realHeight) {
+//    this(0,0,rasterWidth,rasterHeight,lon,lat,realWidth,realHeight);
+//  }
+
+  /**
+   * Erzeugt ein neues Raster in WGS84.
+   * @param rasterWidth Breite des Rasters (in Zellen)
+   * @param rasterHeight Hoehe des Rasters (in Zellen)
+   * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
+   */
+//  public WritableGridArray(int rasterWidth, int rasterHeight, Rectangle2D envelope) {
+//    this(0,0,rasterWidth,rasterHeight,envelope);
+//  }
+
+  /**
+   * Erzeugt ein neues Raster.
+   * @param image Daten
+   * @param envelope Georeferenz und Ausdehnung des Rasters
+   * @param crs CoordinateReferenceSystem fuer das Raster
+   * @return Ein {@link WritableGridArray.Integer}, {@link WritableGridArray.Float} oder
+   *         {@link WritableGridArray.Double}, je nach Datentyp des {@code image}-DataBuffers
+   */
+  public static WritableGridArray create(RenderedImage image, Rectangle2D envelope, CoordinateReferenceSystem crs) {
+    return create(image.getData(),envelope,crs);
+//    int width  = image.getWidth();
+//    int height = image.getHeight();
+//    switch (image.getData().getDataBuffer().getDataType()) {
+//      case DataBuffer.TYPE_BYTE:
+//      case DataBuffer.TYPE_SHORT:
+//      case DataBuffer.TYPE_USHORT:
+//      case DataBuffer.TYPE_INT:    return new WritableGridArray.Integer(width,height,envelope,crs,image.getData());
+//      case DataBuffer.TYPE_FLOAT:  return new WritableGridArray.Float(width,height,envelope,crs,image.getData());
+//      case DataBuffer.TYPE_DOUBLE: return new WritableGridArray.Double(width,height,envelope,crs,image.getData());
+//
+//    }
+//    throw new UnsupportedOperationException("Data type of image not yet supported: "+image.getData().getDataBuffer().getDataType());
+  }
+
+  /**
+   * Erzeugt ein neues Raster in WGS84.
+   * @param image Daten
+   * @param envelope Georeferenz und Ausdehnung des Rasters
+   * @return Ein {@link WritableGridArray.Integer}, {@link WritableGridArray.Float} oder
+   *         {@link WritableGridArray.Double}, je nach Datentyp des {@code image}-DataBuffers
+   */
+  public static WritableGridArray create(RenderedImage image, Rectangle2D envelope) {
+    return create(image,envelope,null);
+  }
+
+  /**
+   * Erzeugt ein neues Raster.
+   * @param image Daten
+   * @param envelope Georeferenz und Ausdehnung des Rasters
+   * @param crs CoordinateReferenceSystem fuer das Raster
+   * @return Ein {@link WritableGridArray.Integer}, {@link WritableGridArray.Float} oder
+   *         {@link WritableGridArray.Double}, je nach Datentyp des {@code image}-DataBuffers
+   */
+  public static WritableGridArray create(Raster raster, Rectangle2D envelope, CoordinateReferenceSystem crs) {
+    int width  = raster.getWidth();
+    int height = raster.getHeight();
+    switch (raster.getDataBuffer().getDataType()) {
+      case DataBuffer.TYPE_BYTE:
+      case DataBuffer.TYPE_SHORT:
+      case DataBuffer.TYPE_USHORT:
+      case DataBuffer.TYPE_INT:    return new WritableGridArray.Integer(width,height,envelope,crs,raster);
+      case DataBuffer.TYPE_FLOAT:  return new WritableGridArray.Float(width,height,envelope,crs,raster);
+      case DataBuffer.TYPE_DOUBLE: return new WritableGridArray.Double(width,height,envelope,crs,raster);
+
+    }
+    throw new UnsupportedOperationException("Data type of image not yet supported: "+raster.getDataBuffer().getDataType());
+  }
+
+  /**
+   * Erzeugt ein neues Raster in WGS84.
+   * @param raster Daten
+   * @param envelope Georeferenz und Ausdehnung des Rasters
+   * @return Ein {@link WritableGridArray.Integer}, {@link WritableGridArray.Float} oder
+   *         {@link WritableGridArray.Double}, je nach Datentyp des {@code raster}-DataBuffers
+   */
+  public static WritableGridArray create(Raster raster, Rectangle2D envelope) {
+    return create(raster,envelope,null);
+  }
+
+  /**
+   * Creates an empty GridArray out of a {@link RasterMetaData} object.
+   * @param metaData the MetaData
+   * @param crs CoordinateReferenceSystem fuer das Raster
+   * @return A {@link WritableGridArray.Integer}, {@link WritableGridArray.Float} or
+   *         {@link WritableGridArray.Double}, depending on the Datatype
+   */
+  public static WritableGridArray createEmpty(RasterMetaData metaData, CoordinateReferenceSystem crs) {
+    switch (metaData.getDataType()) {
+      case DataBuffer.TYPE_INT:    return new WritableGridArray.Integer(metaData.getMinX(),metaData.getMinY(),metaData.getWidth(),metaData.getHeight(),metaData.getX(),metaData.getY(),metaData.getRealWidth(),metaData.getRealHeight(),crs,null);
+      case DataBuffer.TYPE_FLOAT:  return new WritableGridArray.Float(metaData.getMinX(),metaData.getMinY(),metaData.getWidth(),metaData.getHeight(),metaData.getX(),metaData.getY(),metaData.getRealWidth(),metaData.getRealHeight(),crs,null);
+      case DataBuffer.TYPE_DOUBLE: return new WritableGridArray.Double(metaData.getMinX(),metaData.getMinY(),metaData.getWidth(),metaData.getHeight(),metaData.getX(),metaData.getY(),metaData.getRealWidth(),metaData.getRealHeight(),crs,null);
+
+    }
+    throw new UnsupportedOperationException("Data type of image not yet supported!");
+  }
+
+  /**
+   * Creates an empty GridArray out of a {@link RasterMetaData} object. WGS84 is
+   * used for CRS.
+   * @param metaData the MetaData
+   * @return A {@link WritableGridArray.Integer}, {@link WritableGridArray.Float} or
+   *         {@link WritableGridArray.Double}, depending on the Datatype
+   */
+  public static WritableGridArray createEmpty(RasterMetaData metaData) {
+    return createEmpty(metaData,metaData.getCoordinateReferenceSystem());
+  }
+
+  /**
+   * Liefert eine Referenz auf den kompletten Inhalt des Rasters in Form eines
+   * {@link DataBuffer}.
+   */
+  public abstract DataBuffer getDataBuffer();
+
+  /**
+   * Liefert eine Referenz auf den kompletten Inhalt des Rasters.
+   * @return einen 1-dimensionalen Array eines Basis-Datentyps
+   */
+  public abstract Object getData();
+
+  /**
+   * Liefert eine Kopie des kompletten Inhalts des Rasters.
+   * @param data Array in den die Daten geschrieben werden (kann {@code null} sein!)
+   * @return einen 2-dimensionaler Array eines Basis-Datentyps (z.B. {@code float[height][width]})
+   */
+  public abstract Object getData(Object data);
+
+  /**
+   * Macht zur Zeit noch nichts.
+   * @todo WritableGridArray.dispose() implementieren
+   */
+  public void dispose() {
+  }
+
+  /**
+   * Liefert die X-Koordinate der Georeferenz (Longitude) der linken unteren
+   * Ecke des Rasters (Südwest).
+   */
+  public double getX() {
+    return envelope.getX();
+  }
+
+  /**
+   * Liefert die Y-Koordinate der Georeferenz (Latitude) der linken unteren
+   * Ecke des Rasters (Südwest).
+   */
+  public double getY() {
+    return envelope.getY();
+  }
+
+  /**
+   * Liefert die reale Breite des Rasters.
+   */
+  public double getRealWidth() {
+    return envelope.getWidth();
+  }
+
+  /**
+   * Liefert die reale Breite des Rasters.
+   */
+  public double getRealHeight() {
+    return envelope.getHeight();
+  }
+
+  /**
+   * Liefert die Georeferenz (Lat/Lon) und Ausdehnung des Rasters.
+   */
+  public Rectangle2D getEnvelope() {
+    return (Rectangle2D)envelope.clone();
+  }
+
+  /**
+   * Liefert die Breite des Rasters (in Zellen).
+   */
+  public int getWidth() {
+    return this.rasterWidth;
+  }
+
+  /**
+   * Liefert die Hoehe des Rasters (in Zellen).
+   */
+  public int getHeight() {
+    return this.rasterHeight;
+  }
+
+  /**
+   * Liefert den Index der ersten (Südwest) Zelle in X-Richtung.
+   */
+  public int getMinX() {
+    return this.minX;
+  }
+
+  /**
+   * Liefert den Index der ersten Zelle (Südwest) in Y-Richtung.
+   */
+  public int getMinY() {
+    return this.minY;
+  }
+
+  /** Serializes the Grid
+   * @author Dominik Appl
+   * @param s
+   * @throws IOException
+   */
+  private synchronized void writeObject( java.io.ObjectOutputStream s )
+  throws IOException
+  {
+	  //writing all attributes to the outputstream
+	  s.defaultWriteObject();
+	  //writing the transient envelope (which is not serializable)
+	  s.writeDouble(envelope.getX());
+	  s.writeDouble(envelope.getY());
+	  s.writeDouble(envelope.getHeight());
+	  s.writeDouble(envelope.getWidth());
+
+  }
+
+  /** Deserializes the Grid
+   * @author Dominik Appl
+   * @param s
+   * @throws IOException
+   */
+  private synchronized void readObject( java.io.ObjectInputStream s )
+   throws IOException, ClassNotFoundException
+   {
+	  //reading standard fields
+	  s.defaultReadObject();
+	  //reading envelope
+	  double lat = s.readDouble();
+	  double lon = s.readDouble();
+	  double realHeight = s.readDouble();
+	  double realWidth = s.readDouble();
+	  envelope = new Rectangle2D.Double(lat,lon,realWidth,realHeight);
+   }
+
+  /////////////////////////////////////////////////////////////////////////
+  ///////////////////////////   Float - Raster ////////////////////////////
+  /////////////////////////////////////////////////////////////////////////
+  public static class Float extends WritableGridArray {
+    /** Speichert zeilenweise die Daten des {@code float}-Rasters ({@code data[y*w+x])} */
+    protected float[] data = null;
+
+    /**
+     * Erzeugt ein neues {@code float}-Raster.
+     * @param minX Raster-Index der ersten Zelle in X-Richtung
+     * @param minY Raster-Index der ersten Zelle in Y-Richtung
+     * @param rasterWidth Breite des Rasters (in Zellen)
+     * @param rasterHeight Hoehe des Rasters (in Zellen)
+     * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
+     * @param crs Referenzsystem fuer das Raster
+     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss der Array
+     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
+     */
+    public Float(int minX, int minY, int rasterWidth, int rasterHeight, Rectangle2D envelope, CoordinateReferenceSystem crs, float[] data) {
+      super(minX,minY,rasterWidth,rasterHeight,envelope,crs);
+      if ( data == null )
+        data = new float[rasterHeight*rasterWidth];
+      if ( data.length < rasterHeight*rasterWidth )
+        throw new IllegalArgumentException("Array for raster content to small!");
+      this.data = data;
+    }
+
+    /**
+     * Erzeugt ein neues {@code float}-Raster.
+     * @param minX Raster-Index der ersten Zelle in X-Richtung
+     * @param minY Raster-Index der ersten Zelle in Y-Richtung
+     * @param rasterWidth Breite des Rasters (in Zellen)
+     * @param rasterHeight Hoehe des Rasters (in Zellen)
+     * @param lon Georeferenz (Longitude = X-Koordinate)
+     * @param lat Georeferenz (Latitude = Y-Koordinate)
+     * @param realWidth Breite des Rasters (in Metern)
+     * @param realHeight Hoehe des Rasters (in Metern)
+     * @param crs Referenzsystem fuer das Raster
+     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss der Array
+     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
+     */
+    public Float(int minX, int minY, int rasterWidth, int rasterHeight, double lon, double lat, double realWidth, double realHeight, CoordinateReferenceSystem crs, float[] data) {
+      this( minX, minY, rasterWidth, rasterHeight, new Rectangle2D.Double(lon,lat,realWidth,realHeight),crs, data );
+    }
+
+    /**
+     * Erzeugt ein neues leeres {@code float}-Raster.
+     * @param rasterWidth Breite des Rasters (in Zellen)
+     * @param rasterHeight Hoehe des Rasters (in Zellen)
+     * @param lon Georeferenz (Longitude = X-Koordinate)
+     * @param lat Georeferenz (Latitude = Y-Koordinate)
+     * @param realWidth Breite des Rasters (in Metern)
+     * @param realHeight Hoehe des Rasters (in Metern)
+     * @param crs Referenzsystem fuer das Raster
+     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss der Array
+     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
+     */
+    public Float(int rasterWidth, int rasterHeight, double lon, double lat, double realWidth, double realHeight, CoordinateReferenceSystem crs, float[] data) {
+      this(0,0,rasterWidth,rasterHeight,lon,lat,realWidth,realHeight,crs,data);
+    }
+
+    /**
+     * Erzeugt ein neues leeres {@code float}-Raster.
+     * @param rasterWidth Breite des Rasters (in Zellen)
+     * @param rasterHeight Hoehe des Rasters (in Zellen)
+     * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
+     * @param crs Referenzsystem fuer das Raster
+     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss der Array
+     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
+     */
+    public Float(int rasterWidth, int rasterHeight, Rectangle2D envelope, CoordinateReferenceSystem crs, float[] data) {
+      this(0,0,rasterWidth,rasterHeight,envelope,crs,data);
+    }
+
+    /**
+     * Erzeugt ein neues leeres {@code float}-Raster.
+     * @param rasterWidth Breite des Rasters (in Zellen)
+     * @param rasterHeight Hoehe des Rasters (in Zellen)
+     * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
+     * @param crs Referenzsystem fuer das Raster
+     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss der Array
+     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
+     */
+    public Float(int rasterWidth, int rasterHeight, Rectangle2D envelope, CoordinateReferenceSystem crs, float[][] data) {
+      this(0,0,rasterWidth,rasterHeight,envelope,crs,null);
+      // Daten in Array uebernehmen
+      for (int y=0; y<rasterHeight; y++)
+        for (int x=0; x<rasterWidth; x++)
+          this.data[y*rasterWidth+x] = data[x][y];
+    }
+
+    /**
+     * Erzeugt ein neues leeres {@code float}-Raster.
+     * @param rasterWidth Breite des Rasters (in Zellen)
+     * @param rasterHeight Hoehe des Rasters (in Zellen)
+     * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
+     * @param crs Referenzsystem fuer das Raster
+     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss das Raster
+     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
+     */
+    public Float(int rasterWidth, int rasterHeight, Rectangle2D envelope, CoordinateReferenceSystem crs, Raster data) {
+      this(0,0,rasterWidth,rasterHeight,envelope,crs,null);
+      // Daten in Array uebernehmen
+      data.getPixels(0,0,rasterWidth,rasterHeight,this.data);
+    }
+
+    /**
+     * Liefert eine Referenz auf den kompletten Inhalt des Raster.
+     * @return {@code float[height*width]}-Array.
+     */
+    public float[] getData() {
+      return this.data;
+    }
+
+    /**
+     * Liefert eine Referenz auf den kompletten Inhalt des Rasters in Form eines
+     * {@link DataBuffer}.
+     */
+    public DataBufferFloat getDataBuffer() {
+      return new DataBufferFloat(data,data.length);
+    }
+
+    /**
+     * Liefert eine Kopie des kompletten Inhalts des Rasters.
+     * @param data Array in den die Daten geschrieben werden (kann {@code null} sein!)
+     * @return einen {@code float[height][width]}-Array.
+     */
+    public float[][] getData(Object data) {
+      return getData((float[][])data);
+    }
+    /**
+     * Liefert eine Kopie des kompletten Inhalts des Rasters.
+     * @param data Array in den die Daten geschrieben werden (kann {@code null} sein!)
+     * @return {@code float[height][width]}-Array.
+     */
+    public float[][] getData(float[][] data) {
+      if ( data == null )
+        data = new float[rasterHeight][rasterWidth];
+      for (int y=0; y<rasterHeight; y++)
+        for (int x=0; x<rasterWidth; x++)
+          data[y][x] = this.data[y*rasterWidth+x];
+      return data;
+    }
+
+    /**
+     * Liefert eine Kopie des kompletten Inhalts des Rasters. Die {@code float}-Werte
+     * des Rasters werden einfach zu {@code int} gecastet.
+     * @param data Array in den die Daten geschrieben werden (kann {@code null} sein!)
+     * @return {@code int[height][width]}-Array.
+     */
+    public int[][] getData(int[][] data) {
+      if ( data == null )
+        data = new int[rasterHeight][rasterWidth];
+      for (int y=0; y<rasterHeight; y++)
+        for (int x=0; x<rasterWidth; x++)
+          data[y][x] = (int)this.data[y*rasterWidth+x];
+      return data;
+    }
+
+    /**
+     * Liefert eine Kopie des kompletten Inhalts des Rasters. Die {@code float}-Werte
+     * des Rasters werden einfach zu {@code double} gecastet.
+     * @param data Array in den die Daten geschrieben werden (kann {@code null} sein!)
+     * @return {@code double[height][width]}-Array.
+     */
+    public double[][] getData(double[][] data) {
+      if ( data == null )
+        data = new double[rasterHeight][rasterWidth];
+      for (int y=0; y<rasterHeight; y++)
+        for (int x=0; x<rasterWidth; x++)
+          data[y][x] = this.data[y*rasterWidth+x];
+      return data;
+    }
+
+    /**
+     * Liefert die Art der Daten, die im Raster gespeichert werden koennen. Diese
+     * wird durch eine der TYPE-Konstanten in {@link DataBuffer}
+     * repraesentiert.
+     * @return immer {@link DataBuffer#TYPE_FLOAT DataBuffer.TYPE_FLOAT}
+     */
+    public int getSampleType() {
+      return DataBuffer.TYPE_FLOAT;
+    }
+
+    /**
+     * Setzt einen Wert im Raster ueber Raster-Koordinaten.
+     * @param value neuer Wert
+     * @param cell  2D-Raster-Koordinate (Zellenindizes, beginnend bei
+     *              {@link #getMinX()} und {@link #getMinY()})
+     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
+     *            Koordinaten angegeben werden
+     */
+    public void setRasterSample(Object value, int ...cell) {
+      if (cell.length < RASTER_DIM)
+        throw new UnsupportedOperationException(RASTER_DIM +
+                                                " Coordinates expected");
+      if (value == null)
+        throw new UnsupportedOperationException(getClass().getSimpleName() +
+                                                " can not store null-Objects");
+      if (! (value instanceof java.lang.Number))
+        throw new UnsupportedOperationException(getClass().getSimpleName() +
+                                                " only can not store "+value.getClass().getSimpleName()+"-Objects");
+
+      int x = cell[0] - minX;
+      int y = cell[1] - minY;
+      data[y*rasterWidth+x] = ((Number)value).floatValue();
+    }
+
+    /**
+     * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
+     * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+     *             {@link #getMinX()} und {@link #getMinY()})
+     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
+     *            Koordinaten angegeben werden
+     */
+    public java.lang.Float getRasterSample(int ...cell) {
+      if (cell.length < RASTER_DIM)
+        throw new UnsupportedOperationException(RASTER_DIM + " Coordinates expected");
+      int x = cell[0] - minX;
+      int y = cell[1] - minY;
+      return data[y*rasterWidth+x];
+    }
+
+    /**
+     * Liefert einen Wert des Rasters ueber Raster-Koordinaten. Greift direkt
+     * auf den Daten-Array zu und nutzt nicht die generischen Methoden der
+     * Oberklasse.
+     * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+     *             {@link #getMinX()} und {@link #getMinY()})
+     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
+     *            Koordinaten angegeben werden
+     */
+    public float getRasterSampleAsFloat(int... cell) {
+      int x = cell[0] - minX;
+      int y = cell[1] - minY;
+      return data[y*rasterWidth+x];
+    }
+
+    /**
+     * Setzt einen Wert des Rasters ueber Raster-Koordinaten. Greift direkt
+     * auf den Daten-Array zu und nutzt nicht die generischen Methoden der
+     * Oberklasse.
+     * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+     *             {@link #getMinX()} und {@link #getMinY()})
+     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
+     *            Koordinaten angegeben werden
+     */
+    public void setRasterSample(float value, int... cell) {
+      if ( cell.length < RASTER_DIM )
+        throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
+      int x = cell[0] - minX;
+      int y = cell[1] - minY;
+      data[y*rasterWidth+x] = value;
+    }
+
+    /**
+     * Liefert einen Wert des Rasters ueber Geo-Koordinaten. Greift direkt
+     * auf den Daten-Array zu und nutzt nicht die generischen Methoden der
+     * Oberklasse.
+     * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
+     *            Koordinaten angegeben werden
+     */
+    public float getGridSampleAsFloat(double... coord){
+      if ( coord.length < RASTER_DIM )
+        throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
+      // Koordinaten umrechnen in Zellen-Index
+      int cellX = convertRealToRaster(coord[0],0);
+      int cellY = convertRealToRaster(coord[1],1);
+      return data[cellY*rasterWidth + cellX];
+    }
+
+    /**
+     * Setzt einen Wert des Rasters ueber Geo-Koordinaten. Liegt der
+     * Koordinatenwert genau auf der Grenze zwischen zwei Rasterzellen, wird die
+     * naechst groessere Zelle gewaehlt (ausser die Grenze entspricht dem Raster-Rand!).
+     * Greift direkt auf den Daten-Array zu und nutzt nicht die generischen Methoden der
+     * Oberklasse.
+     * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
+     *            Koordinaten angegeben werden
+     */
+    public void setGridSample(float value, int... coord) {
+      if ( coord.length < RASTER_DIM )
+        throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
+      // Koordinaten umrechnen in Zellen-Index
+      int cellX = convertRealToRaster(coord[0],0);
+      int cellY = convertRealToRaster(coord[1],1);
+      data[cellY*rasterWidth+cellX] = value;
+    }
+  }
+
+  /////////////////////////////////////////////////////////////////////////
+  ///////////////////////////   Double - Raster ////////////////////////////
+  /////////////////////////////////////////////////////////////////////////
+  public static class Double extends WritableGridArray {
+    /** Speichert zeilenweise die Daten des {@code double}-Rasters ({@code data[y*w+x])} */
+    protected double[] data = null;
+
+    /**
+     * Erzeugt ein neues {@code double}-Raster.
+     * @param minX Raster-Index der ersten Zelle in X-Richtung
+     * @param minY Raster-Index der ersten Zelle in Y-Richtung
+     * @param rasterWidth Breite des Rasters (in Zellen)
+     * @param rasterHeight Hoehe des Rasters (in Zellen)
+     * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
+     * @param crs Referenzsystem fuer das Raster
+     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss der Array
+     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
+     */
+    public Double(int minX, int minY, int rasterWidth, int rasterHeight, Rectangle2D envelope, CoordinateReferenceSystem crs, double[] data) {
+      super(minX,minY,rasterWidth,rasterHeight,envelope,crs);
+      if ( data == null )
+        data = new double[rasterHeight*rasterWidth];
+      if ( data.length < rasterHeight*rasterWidth )
+        throw new IllegalArgumentException("Array for raster content to small!");
+      this.data = data;
+    }
+
+    /**
+     * Erzeugt ein neues {@code double}-Raster.
+     * @param minX Raster-Index der ersten Zelle in X-Richtung
+     * @param minY Raster-Index der ersten Zelle in Y-Richtung
+     * @param rasterWidth Breite des Rasters (in Zellen)
+     * @param rasterHeight Hoehe des Rasters (in Zellen)
+     * @param lon Georeferenz (Longitude = X-Koordinate)
+     * @param lat Georeferenz (Latitude = Y-Koordinate)
+     * @param realWidth Breite des Rasters (in Metern)
+     * @param realHeight Hoehe des Rasters (in Metern)
+     * @param crs Referenzsystem fuer das Raster
+     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss der Array
+     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
+     */
+    public Double(int minX, int minY, int rasterWidth, int rasterHeight, double lon, double lat, double realWidth, double realHeight, CoordinateReferenceSystem crs, double[] data) {
+      this( minX, minY, rasterWidth, rasterHeight, new Rectangle2D.Double(lon,lat,realWidth,realHeight), crs, data );
+    }
+
+    /**
+     * Erzeugt ein neues leeres {@code double}-Raster.
+     * @param rasterWidth Breite des Rasters (in Zellen)
+     * @param rasterHeight Hoehe des Rasters (in Zellen)
+     * @param lon Georeferenz (Longitude = X-Koordinate)
+     * @param lat Georeferenz (Latitude = Y-Koordinate)
+     * @param realWidth Breite des Rasters (in Metern)
+     * @param realHeight Hoehe des Rasters (in Metern)
+     * @param crs Referenzsystem fuer das Raster
+     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss der Array
+     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
+     */
+    public Double(int rasterWidth, int rasterHeight, double lon, double lat, double realWidth, double realHeight, CoordinateReferenceSystem crs, double[] data) {
+      this(0,0,rasterWidth,rasterHeight,lon,lat,realWidth,realHeight,crs,data);
+    }
+
+    /**
+     * Erzeugt ein neues leeres {@code double}-Raster.
+     * @param rasterWidth Breite des Rasters (in Zellen)
+     * @param rasterHeight Hoehe des Rasters (in Zellen)
+     * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
+     * @param crs Referenzsystem fuer das Raster
+     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss der Array
+     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
+     */
+    public Double(int rasterWidth, int rasterHeight, Rectangle2D envelope, CoordinateReferenceSystem crs, double[] data) {
+      this(0,0,rasterWidth,rasterHeight,envelope,crs,data);
+    }
+
+    /**
+     * Erzeugt ein neues leeres {@code double}-Raster.
+     * @param rasterWidth Breite des Rasters (in Zellen)
+     * @param rasterHeight Hoehe des Rasters (in Zellen)
+     * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
+     * @param crs Referenzsystem fuer das Raster
+     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss der Array
+     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
+     */
+    public Double(int rasterWidth, int rasterHeight, Rectangle2D envelope, CoordinateReferenceSystem crs, double[][] data) {
+      this(0,0,rasterWidth,rasterHeight,envelope,crs,null);
+      // Daten in Array uebernehmen
+      for (int y=0; y<rasterHeight; y++)
+        for (int x=0; x<rasterWidth; x++)
+          this.data[y*rasterWidth+x] = data[x][y];
+    }
+
+    /**
+     * Erzeugt ein neues leeres {@code double}-Raster.
+     * @param rasterWidth Breite des Rasters (in Zellen)
+     * @param rasterHeight Hoehe des Rasters (in Zellen)
+     * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
+     * @param crs Referenzsystem fuer das Raster
+     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss das Raster
+     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
+     */
+    public Double(int rasterWidth, int rasterHeight, Rectangle2D envelope, CoordinateReferenceSystem crs, Raster data) {
+      this(0,0,rasterWidth,rasterHeight,envelope,crs,null);
+      // Daten in Array uebernehmen
+      data.getPixels(0,0,rasterWidth,rasterHeight,this.data);
+    }
+
+    /**
+     * Liefert eine Referenz auf den kompletten Inhalt des Raster.
+     * @return {@code double[height*width]}-Array.
+     */
+    public double[] getData() {
+      return this.data;
+    }
+
+    /**
+     * Liefert eine Referenz auf den kompletten Inhalt des Rasters in Form eines
+     * {@link DataBuffer}.
+     */
+    public DataBufferDouble getDataBuffer() {
+      return new DataBufferDouble(data,data.length);
+    }
+
+    /**
+     * Liefert eine Kopie des kompletten Inhalts des Rasters.
+     * @param data Array in den die Daten geschrieben werden (kann {@code null} sein!)
+     * @return einen {@code double[height][width]}-Array.
+     */
+    public double[][] getData(Object data) {
+      return getData((double[][])data);
+    }
+    /**
+     * Liefert eine Kopie des kompletten Inhalts des Rasters.
+     * @param data Array in den die Daten geschrieben werden (kann {@code null} sein!)
+     * @return {@code double[height][width]}-Array.
+     */
+    public double[][] getData(double[][] data) {
+      if ( data == null )
+        data = new double[rasterHeight][rasterWidth];
+      for (int y=0; y<rasterHeight; y++)
+        for (int x=0; x<rasterWidth; x++)
+          data[y][x] = this.data[y*rasterWidth+x];
+      return data;
+    }
+
+    /**
+     * Liefert eine Kopie des kompletten Inhalts des Rasters. Die {@code double}-Werte
+     * des Rasters werden einfach zu {@code float} gecastet.
+     * @param data Array in den die Daten geschrieben werden (kann {@code null} sein!)
+     * @return {@code float[height][width]}-Array.
+     */
+    public float[][] getData(float[][] data) {
+      if ( data == null )
+        data = new float[rasterHeight][rasterWidth];
+      for (int y=0; y<rasterHeight; y++)
+        for (int x=0; x<rasterWidth; x++)
+          data[y][x] = (float)this.data[y*rasterWidth+x];
+      return data;
+    }
+
+    /**
+     * Liefert eine Kopie des kompletten Inhalts des Rasters. Die {@code double}-Werte
+     * des Rasters werden einfach zu {@code int} gecastet.
+     * @param data Array in den die Daten geschrieben werden (kann {@code null} sein!)
+     * @return {@code int[height][width]}-Array.
+     */
+    public int[][] getData(int[][] data) {
+      if ( data == null )
+        data = new int[rasterHeight][rasterWidth];
+      for (int y=0; y<rasterHeight; y++)
+        for (int x=0; x<rasterWidth; x++)
+          data[y][x] = (int)this.data[y*rasterWidth+x];
+      return data;
+    }
+
+    /**
+     * Liefert die Art der Daten, die im Raster gespeichert werden koennen. Diese
+     * wird durch eine der TYPE-Konstanten in {@link DataBuffer}
+     * repraesentiert.
+     * @return immer {@link DataBuffer#TYPE_DOUBLE DataBuffer.TYPE_DOUBLE}
+     */
+    public int getSampleType() {
+      return DataBuffer.TYPE_DOUBLE;
+    }
+
+    /**
+     * Setzt einen Wert im Raster ueber Raster-Koordinaten.
+     * @param value neuer Wert
+     * @param cell  2D-Raster-Koordinate (Zellenindizes, beginnend bei
+     *              {@link #getMinX()} und {@link #getMinY()})
+     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
+     *            Koordinaten angegeben werden
+     */
+    public void setRasterSample(Object value, int ...cell) {
+      if (cell.length < RASTER_DIM)
+        throw new UnsupportedOperationException(RASTER_DIM + " Coordinates expected");
+      if (value == null)
+        throw new UnsupportedOperationException(getClass().getSimpleName() +
+                                                " can not store null-Objects");
+      if (! (value instanceof java.lang.Number))
+        throw new UnsupportedOperationException(getClass().getSimpleName() +
+                                                " only can not store "+value.getClass().getSimpleName()+"-Objects");
+      int x = cell[0] - minX;
+      int y = cell[1] - minY;
+      data[y*rasterWidth+x] = ((java.lang.Number)value).doubleValue();
+    }
+
+    /**
+     * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
+     * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+     *             {@link #getMinX()} und {@link #getMinY()})
+     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
+     *            Koordinaten angegeben werden
+     */
+    public java.lang.Double getRasterSample(int ...cell) {
+      if (cell.length < RASTER_DIM)
+        throw new UnsupportedOperationException(RASTER_DIM + " Coordinates expected");
+      int x = cell[0] - minX;
+      int y = cell[1] - minY;
+      return data[y*rasterWidth+x];
+    }
+
+    /**
+     * Liefert einen Wert des Rasters ueber Raster-Koordinaten. Greift direkt
+     * auf den Daten-Array zu und nutzt nicht die generischen Methoden der
+     * Oberklasse.
+     * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+     *             {@link #getMinX()} und {@link #getMinY()})
+     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
+     *            Koordinaten angegeben werden
+     */
+    public double getRasterSampleAsDouble(int... cell) {
+      int x = cell[0] - minX;
+      int y = cell[1] - minY;
+      return data[y*rasterWidth+x];
+    }
+
+    /**
+     * Setzt einen Wert des Rasters ueber Raster-Koordinaten. Greift direkt
+     * auf den Daten-Array zu und nutzt nicht die generischen Methoden der
+     * Oberklasse.
+     * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+     *             {@link #getMinX()} und {@link #getMinY()})
+     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
+     *            Koordinaten angegeben werden
+     */
+    public void setRasterSample(double value, int... cell) {
+      if ( cell.length < RASTER_DIM )
+        throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
+      int x = cell[0] - minX;
+      int y = cell[1] - minY;
+      data[y*rasterWidth+x] = value;
+    }
+
+    /**
+     * Liefert einen Wert des Rasters ueber Geo-Koordinaten. Greift direkt
+     * auf den Daten-Array zu und nutzt nicht die generischen Methoden der
+     * Oberklasse.
+     * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
+     *            Koordinaten angegeben werden
+     */
+    public double getGridSampleAsDouble(double... coord){
+      if ( coord.length < RASTER_DIM )
+        throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
+      // Koordinaten umrechnen in Zellen-Index
+      int cellX = convertRealToRaster(coord[0],0);
+      int cellY = convertRealToRaster(coord[1],1);
+      return data[cellY*rasterWidth + cellX];
+    }
+
+    /**
+     * Setzt einen Wert des Rasters ueber Geo-Koordinaten. Liegt der
+     * Koordinatenwert genau auf der Grenze zwischen zwei Rasterzellen, wird die
+     * naechst groessere Zelle gewaehlt (ausser die Grenze entspricht dem Raster-Rand!).
+     * Greift direkt auf den Daten-Array zu und nutzt nicht die generischen Methoden der
+     * Oberklasse.
+     * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
+     *            Koordinaten angegeben werden
+     */
+    public void setGridSample(double value, int... coord) {
+      if ( coord.length < RASTER_DIM )
+        throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
+      // Koordinaten umrechnen in Zellen-Index
+      int cellX = convertRealToRaster(coord[0],0);
+      int cellY = convertRealToRaster(coord[1],1);
+      data[cellY*rasterWidth+cellX] = value;
+    }
+  }
+
+  /////////////////////////////////////////////////////////////////////////
+  ///////////////////////////   Integer - Raster ////////////////////////////
+  /////////////////////////////////////////////////////////////////////////
+  public static class Integer extends WritableGridArray {
+    /** Speichert zeilenweise die Daten des {@code int}-Rasters ({@code data[y*w+x])} */
+    protected int[] data = null;
+
+    /**
+     * Erzeugt ein neues {@code int}-Raster.
+     * @param minX Raster-Index der ersten Zelle in X-Richtung
+     * @param minY Raster-Index der ersten Zelle in Y-Richtung
+     * @param rasterWidth Breite des Rasters (in Zellen)
+     * @param rasterHeight Hoehe des Rasters (in Zellen)
+     * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
+     * @param crs Referenzsystem fuer das Raster
+     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss der Array
+     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
+     */
+    public Integer(int minX, int minY, int rasterWidth, int rasterHeight, Rectangle2D envelope, CoordinateReferenceSystem crs, int[] data) {
+      super(minX,minY,rasterWidth,rasterHeight,envelope,crs);
+      if ( data == null )
+        data = new int[rasterHeight*rasterWidth];
+      if ( data.length < rasterHeight*rasterWidth )
+        throw new IllegalArgumentException("Array for raster content to small!");
+      this.data = data;
+    }
+
+    /**
+     * Erzeugt ein neues {@code int}-Raster.
+     * @param minX Raster-Index der ersten Zelle in X-Richtung
+     * @param minY Raster-Index der ersten Zelle in Y-Richtung
+     * @param rasterWidth Breite des Rasters (in Zellen)
+     * @param rasterHeight Hoehe des Rasters (in Zellen)
+     * @param lon Georeferenz (Longitude = X-Koordinate)
+     * @param lat Georeferenz (Latitude = Y-Koordinate)
+     * @param realWidth Breite des Rasters (in Metern)
+     * @param realHeight Hoehe des Rasters (in Metern)
+     * @param crs Referenzsystem fuer das Raster
+     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss der Array
+     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
+     */
+    public Integer(int minX, int minY, int rasterWidth, int rasterHeight, double lon, double lat, double realWidth, double realHeight, CoordinateReferenceSystem crs, int[] data) {
+      this( minX, minY, rasterWidth, rasterHeight, new Rectangle2D.Double(lon,lat,realWidth,realHeight),crs , data );
+    }
+
+    /**
+     * Erzeugt ein neues leeres {@code int}-Raster.
+     * @param rasterWidth Breite des Rasters (in Zellen)
+     * @param rasterHeight Hoehe des Rasters (in Zellen)
+     * @param lon Georeferenz (Longitude = X-Koordinate)
+     * @param lat Georeferenz (Latitude = Y-Koordinate)
+     * @param realWidth Breite des Rasters (in Metern)
+     * @param realHeight Hoehe des Rasters (in Metern)
+     * @param crs Referenzsystem fuer das Raster
+     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss der Array
+     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
+     */
+    public Integer(int rasterWidth, int rasterHeight, double lon, double lat, double realWidth, double realHeight, CoordinateReferenceSystem crs, int[] data) {
+      this(0,0,rasterWidth,rasterHeight,lon,lat,realWidth,realHeight,crs,data);
+    }
+
+    /**
+     * Erzeugt ein neues leeres {@code int}-Raster.
+     * @param rasterWidth Breite des Rasters (in Zellen)
+     * @param rasterHeight Hoehe des Rasters (in Zellen)
+     * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
+     * @param crs Referenzsystem fuer das Raster
+     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss der Array
+     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
+     */
+    public Integer(int rasterWidth, int rasterHeight, Rectangle2D envelope, CoordinateReferenceSystem crs, int[] data) {
+      this(0,0,rasterWidth,rasterHeight,envelope,crs,data);
+    }
+
+    /**
+     * Erzeugt ein neues leeres {@code int}-Raster.
+     * @param rasterWidth Breite des Rasters (in Zellen)
+     * @param rasterHeight Hoehe des Rasters (in Zellen)
+     * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
+     * @param crs Referenzsystem fuer das Raster
+     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss der Array
+     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
+     */
+    public Integer(int rasterWidth, int rasterHeight, Rectangle2D envelope, CoordinateReferenceSystem crs, int[][] data) {
+      this(0,0,rasterWidth,rasterHeight,envelope,crs,null);
+      // Daten in Array uebernehmen
+      for (int y=0; y<rasterHeight; y++)
+        for (int x=0; x<rasterWidth; x++)
+          this.data[y*rasterWidth+x] = data[x][y];
+    }
+
+    /**
+     * Erzeugt ein neues leeres {@code int}-Raster.
+     * @param rasterWidth Breite des Rasters (in Zellen)
+     * @param rasterHeight Hoehe des Rasters (in Zellen)
+     * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
+     * @param crs Referenzsystem fuer das Raster
+     * @param data Inhalt des Rasters (wenn nicht {@code null}, muss das Raster
+     *             mindestens die Groesse {@code rasterWidth * rasterHeight} haben)
+     */
+    public Integer(int rasterWidth, int rasterHeight, Rectangle2D envelope, CoordinateReferenceSystem crs, Raster data) {
+      this(0,0,rasterWidth,rasterHeight,envelope,crs,null);
+      // Daten in Array uebernehmen
+      data.getPixels(0,0,rasterWidth,rasterHeight,this.data);
+    }
+
+    /**
+     * Liefert eine Referenz auf den kompletten Inhalt des Raster.
+     * @return {@code int[height*width]}-Array.
+     */
+    public int[] getData() {
+      return this.data;
+    }
+
+    /**
+     * Liefert eine Referenz auf den kompletten Inhalt des Rasters in Form eines
+     * {@link DataBuffer}.
+     */
+    public DataBufferInt getDataBuffer() {
+      return new DataBufferInt(data,data.length);
+    }
+
+    /**
+     * Liefert eine Kopie des kompletten Inhalts des Rasters.
+     * @param data Array in den die Daten geschrieben werden (kann {@code null} sein!)
+     * @return einen {@code int[height][width]}-Array.
+     */
+    public int[][] getData(Object data) {
+      return getData((int[][])data);
+    }
+    /**
+     * Liefert eine Kopie des kompletten Inhalts des Rasters.
+     * @param data Array in den die Daten geschrieben werden (kann {@code null} sein!)
+     * @return {@code int[height][width]}-Array.
+     */
+    public int[][] getData(int[][] data) {
+      if ( data == null )
+        data = new int[rasterHeight][rasterWidth];
+      for (int y=0; y<rasterHeight; y++)
+        for (int x=0; x<rasterWidth; x++)
+          data[y][x] = this.data[y*rasterWidth+x];
+      return data;
+    }
+
+    /**
+     * Liefert eine Kopie des kompletten Inhalts des Rasters. Die {@code int}-Werte
+     * des Rasters werden einfach zu {@code float} gecastet.
+     * @param data Array in den die Daten geschrieben werden (kann {@code null} sein!)
+     * @return {@code float[height][width]}-Array.
+     */
+    public float[][] getData(float[][] data) {
+      if ( data == null )
+        data = new float[rasterHeight][rasterWidth];
+      for (int y=0; y<rasterHeight; y++)
+        for (int x=0; x<rasterWidth; x++)
+          data[y][x] = this.data[y*rasterWidth+x];
+      return data;
+    }
+
+    /**
+     * Liefert eine Kopie des kompletten Inhalts des Rasters. Die {@code int}-Werte
+     * des Rasters werden einfach zu {@code double} gecastet.
+     * @param data Array in den die Daten geschrieben werden (kann {@code null} sein!)
+     * @return {@code double[height][width]}-Array.
+     */
+    public double[][] getData(double[][] data) {
+      if ( data == null )
+        data = new double[rasterHeight][rasterWidth];
+      for (int y=0; y<rasterHeight; y++)
+        for (int x=0; x<rasterWidth; x++)
+          data[y][x] = this.data[y*rasterWidth+x];
+      return data;
+    }
+
+    /**
+     * Liefert die Art der Daten, die im Raster gespeichert werden koennen. Diese
+     * wird durch eine der TYPE-Konstanten in {@link DataBuffer}
+     * repraesentiert.
+     * @return immer {@link DataBuffer#TYPE_INT DataBuffer.TYPE_INT}
+     */
+    public int getSampleType() {
+      return DataBuffer.TYPE_INT;
+    }
+
+    /**
+     * Setzt einen Wert im Raster ueber Raster-Koordinaten.
+     * @param value neuer Wert
+     * @param cell  2D-Raster-Koordinate (Zellenindizes, beginnend bei
+     *              {@link #getMinX()} und {@link #getMinY()})
+     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
+     *            Koordinaten angegeben werden
+     */
+    public void setRasterSample(Object value, int ...cell) {
+      if (cell.length < RASTER_DIM)
+        throw new UnsupportedOperationException(RASTER_DIM + " Coordinates expected");
+      if (value == null)
+        throw new UnsupportedOperationException(getClass().getSimpleName() +
+                                                " can not store null-Objects");
+      if (! (value instanceof java.lang.Number))
+        throw new UnsupportedOperationException(getClass().getSimpleName() +
+                                                " only can not store "+value.getClass().getSimpleName()+"-Objects");
+      int x = cell[0] - minX;
+      int y = cell[1] - minY;
+      data[y*rasterWidth+x] = ((java.lang.Number)value).intValue();
+    }
+
+    /**
+     * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
+     * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+     *             {@link #getMinX()} und {@link #getMinY()})
+     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
+     *            Koordinaten angegeben werden
+     */
+    public java.lang.Integer getRasterSample(int ...cell) {
+      if (cell.length < RASTER_DIM)
+        throw new UnsupportedOperationException(RASTER_DIM + " Coordinates expected");
+      int x = cell[0] - minX;
+      int y = cell[1] - minY;
+      return data[y*rasterWidth+x];
+    }
+
+    /**
+     * Liefert einen Wert des Rasters ueber Raster-Koordinaten. Greift direkt
+     * auf den Daten-Array zu und nutzt nicht die generischen Methoden der
+     * Oberklasse.
+     * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+     *             {@link #getMinX()} und {@link #getMinY()})
+     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
+     *            Koordinaten angegeben werden
+     */
+    public int getRasterSampleAsInt(int... cell) {
+      int x = cell[0] - minX;
+      int y = cell[1] - minY;
+      return data[y*rasterWidth+x];
+    }
+
+    /**
+     * Setzt einen Wert des Rasters ueber Raster-Koordinaten. Greift direkt
+     * auf den Daten-Array zu und nutzt nicht die generischen Methoden der
+     * Oberklasse.
+     * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+     *             {@link #getMinX()} und {@link #getMinY()})
+     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
+     *            Koordinaten angegeben werden
+     */
+    public void setRasterSample(int value, int... cell) {
+      if ( cell.length < RASTER_DIM )
+        throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
+      int x = cell[0] - minX;
+      int y = cell[1] - minY;
+      data[y*rasterWidth+x] = value;
+    }
+
+    /**
+     * Liefert einen Wert des Rasters ueber Geo-Koordinaten. Greift direkt
+     * auf den Daten-Array zu und nutzt nicht die generischen Methoden der
+     * Oberklasse.
+     * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
+     *            Koordinaten angegeben werden
+     */
+    public int getGridSampleAsInt(double... coord){
+      if ( coord.length < RASTER_DIM )
+        throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
+      // Koordinaten umrechnen in Zellen-Index
+      int cellX = convertRealToRaster(coord[0],0);
+      int cellY = convertRealToRaster(coord[1],1);
+      return data[cellY*rasterWidth + cellX];
+    }
+
+    /**
+     * Setzt einen Wert des Rasters ueber Geo-Koordinaten. Liegt der
+     * Koordinatenwert genau auf der Grenze zwischen zwei Rasterzellen, wird die
+     * naechst groessere Zelle gewaehlt (ausser die Grenze entspricht dem Raster-Rand!).
+     * Greift direkt auf den Daten-Array zu und nutzt nicht die generischen Methoden der
+     * Oberklasse.
+     * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+     * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
+     *            Koordinaten angegeben werden
+     */
+    public void setGridSample(int value, int... coord) {
+      if ( coord.length < RASTER_DIM )
+        throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
+      // Koordinaten umrechnen in Zellen-Index
+      int cellX = convertRealToRaster(coord[0],0);
+      int cellY = convertRealToRaster(coord[1],1);
+      data[cellY*rasterWidth+cellX] = value;
+    }
+  }
+}

Modified: trunk/src/schmitzm/data/WritableGridRaster.java
===================================================================
--- trunk/src/schmitzm/data/WritableGridRaster.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/WritableGridRaster.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,508 +1,526 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.data;
-
-import java.awt.Point;
-import java.awt.geom.Rectangle2D;
-import java.awt.image.ComponentSampleModel;
-import java.awt.image.DataBuffer;
-import java.awt.image.WritableRaster;
-
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-
-import schmitzm.geotools.GTUtil;
-import appl.data.LoadingException;
-
-/**
- * Diese Klasse stellt eine Implementierung von {@link WritableGrid} dar und
- * basiert auf der Standard-Java Raster-Implementierung {@link WritableRaster}.
- * Auch wenn {@link WritableRaster} prinzipell mehrere Dimensionen (Baender)
- * zulaesst, sind die Zugriffsmethoden dieser Klasse auf ein Band beschraenkt.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class WritableGridRaster extends WritableRaster implements WritableGrid {
-  /**
-   * Die Dimension des Rasters (2).
-   */
-  public static final int RASTER_DIM = 2;
-
-  private static final int band = 0;
-
-  /**
-   * Speichert die Geo-Referenz (Longitude, Latitude, Breite, Hoehe) des
-   * Rasters.
-   */
-  protected Rectangle2D envelope;
-
-  /**
-   * Speichert das CRS des Rasters. Default ist WGS84.
-   */
-  protected CoordinateReferenceSystem crs = GTUtil.WGS84;
-
-  /**
-   * Erzeugt ein georeferenziertes Raster aus einem nicht-georeferenzierten.
-   * @param raster   Datenbasis fuer das Raster
-   * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
-   * @param crs      CoordinateReferenceSystem des Rasters
-   * @see DataBuffer
-   */
-  public WritableGridRaster(WritableRaster raster, Rectangle2D envelope, CoordinateReferenceSystem crs) {
-    super( new ComponentSampleModel(raster.getDataBuffer().getDataType(),
-                                    raster.getWidth(),
-                                    raster.getHeight(),
-                                    1,
-                                    raster.getWidth(),
-                                    new int[] {0}),
-           raster.getDataBuffer(),
-           new Point(raster.getMinX(), raster.getMinY())
-    );
-    this.envelope = envelope;
-    this.crs      = ( crs == null ) ? GTUtil.WGS84 : crs;
-  }
-
-  /**
-   * Erzeugt ein georeferenziertes Raster aus einem nicht-georeferenzierten.
-   * Als CRS wird WGS84 verwendet.
-   * @param raster   Datenbasis fuer das Raster
-   * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
-   * @see DataBuffer
-   */
-  public WritableGridRaster(WritableRaster raster, Rectangle2D envelope) {
-    this(raster,envelope,null);
-  }
-
-  /**
-   * Erzeugt ein neues Raster.
-   * @param dataType Im Raster zu speichernder Datentyp (siehe {@link DataBuffer})
-   * @param minX Raster-Index der ersten Zelle in X-Richtung
-   * @param minY Raster-Index der ersten Zelle in Y-Richtung
-   * @param rasterWidth Breite des Rasters (in Zellen)
-   * @param rasterHeight Hoehe des Rasters (in Zellen)
-   * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
-   * @param crs CoordinateReferenceSystem des Rasters
-   * @see DataBuffer
-   */
-  public WritableGridRaster(int dataType, int minX, int minY, int rasterWidth, int rasterHeight, Rectangle2D envelope, CoordinateReferenceSystem crs) {
-    super( new ComponentSampleModel(dataType,
-                                    rasterWidth,
-                                    rasterHeight,
-                                    1,
-                                    rasterWidth,
-                                    new int[] {0}),
-           new Point(minX,minY)
-    );
-    this.envelope = envelope;
-    this.crs      = ( crs == null ) ? GTUtil.WGS84 : crs;
-  }
-
-  /**
-   * Erzeugt ein neues Raster in WGS84.
-   * @param dataType Im Raster zu speichernder Datentyp (siehe {@link DataBuffer})
-   * @param minX Raster-Index der ersten Zelle in X-Richtung
-   * @param minY Raster-Index der ersten Zelle in Y-Richtung
-   * @param rasterWidth Breite des Rasters (in Zellen)
-   * @param rasterHeight Hoehe des Rasters (in Zellen)
-   * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
-   * @see DataBuffer
-   */
-  public WritableGridRaster(int dataType, int minX, int minY, int rasterWidth, int rasterHeight, Rectangle2D envelope) {
-    this(dataType,minX,minY,rasterWidth,rasterHeight,envelope,null);
-  }
-
-  /**
-   * Erzeugt ein neues Raster.
-   * @param dataType Im Raster zu speichernder Datentyp (siehe {@link DataBuffer})
-   * @param minX Raster-Index der ersten Zelle in X-Richtung
-   * @param minY Raster-Index der ersten Zelle in Y-Richtung
-   * @param rasterWidth Breite des Rasters (in Zellen)
-   * @param rasterHeight Hoehe des Rasters (in Zellen)
-   * @param lon Georeferenz (Longitude = X-Koordinate)
-   * @param lat Georeferenz (Latitude = Y-Koordinate)
-   * @param realWidth Breite des Rasters (in Metern)
-   * @param realHeight Hoehe des Rasters (in Metern)
-   * @param crs CoordinateReferenceSystem des Rasters
-   * @see DataBuffer
-   */
-  public WritableGridRaster(int dataType, int minX, int minY, int rasterWidth, int rasterHeight, double lon, double lat, double realWidth, double realHeight, CoordinateReferenceSystem crs) {
-    this( dataType, minX, minY, rasterWidth, rasterHeight, new Rectangle2D.Double(lon,lat,realWidth,realHeight), crs );
-  }
-
-  /**
-   * Erzeugt ein neues Raster.
-   * @param dataType Im Raster zu speichernder Datentyp (siehe {@link DataBuffer})
-   * @param rasterWidth Breite des Rasters (in Zellen)
-   * @param rasterHeight Hoehe des Rasters (in Zellen)
-   * @param lon Georeferenz (Longitude = X-Koordinate)
-   * @param lat Georeferenz (Latitude = Y-Koordinate)
-   * @param realWidth Breite des Rasters (in Metern)
-   * @param realHeight Hoehe des Rasters (in Metern)
-   * @param crs CoordinateReferenceSystem des Rasters
-   * @see DataBuffer
-   */
-  public WritableGridRaster(int dataType, int rasterWidth, int rasterHeight, double lon, double lat, double realWidth, double realHeight, CoordinateReferenceSystem crs) {
-    this(dataType,0,0,rasterWidth,rasterHeight,lon,lat,realWidth,realHeight,crs);
-  }
-
-  /**
-   * Erzeugt ein neues Raster.
-   * @param dataType Im Raster zu speichernder Datentyp (siehe {@link DataBuffer})
-   * @param rasterWidth Breite des Rasters (in Zellen)
-   * @param rasterHeight Hoehe des Rasters (in Zellen)
-   * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
-   * @param crs CoordinateReferenceSystem des Rasters
-   * @see DataBuffer
-   */
-  public WritableGridRaster(int dataType, int rasterWidth, int rasterHeight, Rectangle2D envelope, CoordinateReferenceSystem crs) {
-    this(dataType,0,0,rasterWidth,rasterHeight,envelope,crs);
-  }
-
-  /**
-   * Macht zur Zeit noch nichts.
-   * @todo WritableGridRaster.dispose() implementieren
-   */
-  public void dispose() {
-  }
-
-  /**
-   * Liefert das {@link CoordinateReferenceSystem} in dem das Raster
-   * dargestellt ist.
-   */
-  public CoordinateReferenceSystem getCoordinateReferenceSystem() {
-    return this.crs;
-  }
-
-  /**
-   * Liefert die X-Koordinate der Georeferenz (Longitude) der linken unteren
-   * Ecke des Rasters (Südwest).
-   * ((offtopic: Südwest ist das Gegenteil von Nördost))
-   */
-  public double getX() {
-    return envelope.getX();
-  }
-
-  /**
-   * Liefert die Y-Koordinate der Georeferenz (Latitude) der linken unteren
-   * Ecke des Rasters (Südwest).
-   */
-  public double getY() {
-    return envelope.getY();
-  }
-
-  /**
-   * Liefert die reale Breite des Rasters.
-   */
-  public double getRealWidth() {
-    return envelope.getWidth();
-  }
-
-  /**
-   * Liefert die reale Breite des Rasters.
-   */
-  public double getRealHeight() {
-    return envelope.getHeight();
-  }
-
-  /**
-   * Liefert die Georeferenz (Lat/Lon) und Ausdehnung des Rasters.
-   */
-  public Rectangle2D getEnvelope() {
-    return (Rectangle2D)envelope.clone();
-  }
-
-  /**
-   * Liefert die reale Breite einer Rasterzelle.
-   * @return <code>getRealWidth() / getWidth()</code>
-   */
-  public double getCellWidth() {
-    return getRealWidth() / getWidth();
-  }
-
-  /**
-   * Liefert die reale Breite einer Rasterzelle.
-   * @return <code>getRealHeight() / getHeight()</code>
-   */
-  public double getCellHeight() {
-    return getRealHeight() / getHeight();
-  }
-
-  /**
-   * Liefert die Art der Daten, die im Raster gespeichert werden koennen. Diese
-   * wird durch eine der TYPE-Konstanten in {@link DataBuffer}
-   * repraesentiert.
-   */
-  public int getSampleType() {
-    return getDataBuffer().getDataType();
-  }
-
-  /**
-   * Setzt einen Wert im Raster ueber Raster-Koordinaten.
-   * @param value neuer Wert
-   * @param cell  2D-Raster-Koordinate (Zellenindizes, beginnend bei
-   *              {@link #getMinX()} und {@link #getMinY()})
-   * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
-   *            Koordinaten angegeben werden
-   */
-  public void setRasterSample(Object value, int... cell) {
-    if ( cell.length < RASTER_DIM )
-      throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
-//    // Bei 'raster' (WritableRaster) beginnen die Raster-Koordinaten in der
-//    // linken oberen Ecke. Im Grid soll die Zaehlung jedoch in der linken unteren
-//    // Ecke beginnen -> Y-Koordinate umrechnen
-//    int x = cell[0];
-//    int y = getMinY() + getHeight()-1 - cell[1];
-    // Bei 'raster' (WritableRaster) beginnen die Raster-Koordinaten in der
-    // linken oberen Ecke. Im Grid soll es genauso sein!!
-    int x = cell[0];
-    int y = cell[1];
-
-    switch ( getSampleType() ) {
-      case DataBuffer.TYPE_BYTE:
-      case DataBuffer.TYPE_SHORT:
-      case DataBuffer.TYPE_USHORT:
-      case DataBuffer.TYPE_INT: setSample(x,y,band,((Number)value).intValue());
-                                break;
-      case DataBuffer.TYPE_FLOAT: setSample(x,y,band,((Number)value).floatValue());
-                                  break;
-      case DataBuffer.TYPE_DOUBLE: setSample(x,y,band,((Number)value).doubleValue());
-                                   break;
-    }
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
-   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-   *             {@link #getMinX()} und {@link #getMinY()})
-   * @return je nach {@linkplain #getSampleType() Art} des Rasters einen
-   *         <code>int</code>, <code>float</code> oder <code>double</code>
-   * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
-   *            Koordinaten angegeben werden
-   */
-  public Object getRasterSample(int... cell) {
-    if ( cell.length < RASTER_DIM )
-      throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
-//    // Bei 'raster' (WritableRaster) beginnen die Raster-Koordinaten in der
-//    // linken oberen Ecke. Im Grid soll die Zaehlung jedoch in der linken unteren
-//    // Ecke beginnen -> Y-Koordinate umrechnen
-//    int x = cell[0];
-//    int y = getMinY() + getHeight()-1 - cell[1];
-    // Bei 'raster' (WritableRaster) beginnen die Raster-Koordinaten in der
-    // linken oberen Ecke. Im Grid soll es genauso sein!!
-    int x = cell[0];
-    int y = cell[1];
-    switch ( getSampleType() ) {
-      case DataBuffer.TYPE_BYTE:
-      case DataBuffer.TYPE_SHORT:
-      case DataBuffer.TYPE_USHORT:
-      case DataBuffer.TYPE_INT: return getSample(x,y,band);
-      case DataBuffer.TYPE_FLOAT: return getSampleFloat(x,y,band);
-      case DataBuffer.TYPE_DOUBLE: return getSampleDouble(x,y,band);
-    }
-    return getSample(x,y,band);
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
-   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-   *             {@link #getMinX()} und {@link #getMinY()})
-   */
-  public short getRasterSampleAsShort(int... cell) {
-    return ((Number)getRasterSample(cell)).shortValue();
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
-   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-   *             {@link #getMinX()} und {@link #getMinY()})
-   */
-  public byte getRasterSampleAsByte(int... cell) {
-    return ((Number)getRasterSample(cell)).byteValue();
-  }
-
-
-  /**
-   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
-   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-   *             {@link #getMinX()} und {@link #getMinY()})
-   */
-  public int getRasterSampleAsInt(int... cell) {
-    return ((Number)getRasterSample(cell)).intValue();
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
-   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-   *             {@link #getMinX()} und {@link #getMinY()})
-   */
-  public long getRasterSampleAsLong(int... cell) {
-    return ((Number)getRasterSample(cell)).longValue();
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
-   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-   *             {@link #getMinX()} und {@link #getMinY()})
-   */
-  public float getRasterSampleAsFloat(int... cell) {
-    return ((Number)getRasterSample(cell)).floatValue();
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
-   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-   *             {@link #getMinX()} und {@link #getMinY()})
-   */
-  public double getRasterSampleAsDouble(int... cell) {
-    return ((Number)getRasterSample(cell)).doubleValue();
-  }
-
-  /**
-   * Setzt einen Wert des Rasters ueber Geo-Koordinaten. Liegt der
-   * Koordinatenwert genau auf der Grenze zwischen zwei Rasterzellen, wird die
-   * naechst groessere Zelle gewaehlt (ausser die Grenze entspricht dem Raster-Rand!).
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
-   *            Koordinaten angegeben werden
-   */
-  public void setGridSample(Object value, double... coord) {
-    if ( coord.length < RASTER_DIM )
-      throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
-    // Koordinaten umrechnen in Zellen-Index
-    int cellX = convertRealToRaster(coord[0],0);
-    int cellY = convertRealToRaster(coord[1],1);
-    setRasterSample(value,cellX,cellY);
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
-   * Liegt der Koordinatenwert genau auf der Grenze zwischen zwei Rasterzellen,
-   * wird die naechst groessere Zelle gewaehlt (ausser die Grenze entspricht
-   * dem Raster-Rand!).
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
-   *            Koordinaten angegeben werden
-   */
-  public Object getGridSample(double... coord) {
-    if ( coord.length < RASTER_DIM )
-      throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
-    // Koordinaten umrechnen in Zellen-Index
-    int cellX = convertRealToRaster(coord[0],0);
-    int cellY = convertRealToRaster(coord[1],1);
-    return getRasterSample(cellX,cellY);
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   */
-  public short getGridSampleAsShort(double... coord) {
-    return ((Number)getGridSample(coord)).shortValue();
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   */
-  public byte getGridSampleAsByte(double... coord){
-    return ((Number)getGridSample(coord)).byteValue();
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   */
-  public int getGridSampleAsInt(double... coord){
-    return ((Number)getGridSample(coord)).intValue();
-  }
-
-
-  /**
-   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   */
-  public long getGridSampleAsLong(double... coord){
-    return ((Number)getGridSample(coord)).longValue();
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   */
-  public float getGridSampleAsFloat(double... coord){
-    return ((Number)getGridSample(coord)).floatValue();
-  }
-
-
-  /**
-   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   */
-  public double getGridSampleAsDouble(double... coord){
-    return ((Number)getGridSample(coord)).doubleValue();
-  }
-
-  /**
-   * Konvertiert eine reale Koordinate in eine Zellennummer. Liegt der
-   * Koordinatenwert genau auf der Grenze zwischen zwei Rasterzellen, wird
-   * die naechst "groessere" Zellegewaehlt.
-   * Ausnahme bildet der Rand des Rasters. Hier wird die kleinere Zelle
-   * (also die letzte) herangezogen
-   * @param coord Georeferenz-Koordinate
-   * @param dim   Dimension, in der die Umrechnung erfolgen soll
-   * @exception UnsupportedOperationException falls eine ungueltige Dimension
-   *            angegeben wird (nur Werte 0 <= coord < {@link #RASTER_DIM} sind
-   *            zulaessig
-   */
-  public int convertRealToRaster(double coord, int dim) {
-    return AbstractWritableGrid.convertRealToRaster(this,coord,dim);
-  }
-
-  /**
-   * Konvertiert eine Zellennummer in reale Koordinate. Dabei wird die
-   * Koordinate der Zellenmitte zurueckgegeben.
-   * @param cell  Rasterzellen-Koordinate
-   * @param dim   Dimension, in der die Umrechnung erfolgen soll
-   * @exception UnsupportedOperationException falls eine ungueltige Dimension
-   *            angegeben wird (nur Werte 0 <= coord < {@link #RASTER_DIM} sind
-   *            zulaessig
-   */
-  public double convertRasterToReal(int cell, int dim) {
-    return AbstractWritableGrid.convertRasterToReal(this,cell,dim);
-  }
-
-  /**
-   * This class does not support late loading itself!
-   * @return false;
-   * @see appl.data.LateLoadable#unloadData()
-   * @see appl.data.LateLoadable#isLateLoadable()
-   */
-  public boolean isLateLoadable() {
-    return false;
-  }
-
-  /**
-   * This class  does not support late loading!
-   * @see appl.data.LateLoadable#unloadData()
-   * @see appl.data.LateLoadable#loadData()
-   */
-  public void loadData() throws LoadingException {
-  }
-
-  /**
-   * Does nothing!
-   * This class does not support late loading!
-   * @see appl.data.LateLoadable#unloadData()
-   */
-  public void unloadData() {
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data;
+
+import java.awt.Point;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.ComponentSampleModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.WritableRaster;
+
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+
+import schmitzm.geotools.GTUtil;
+import appl.data.LoadingException;
+
+/**
+ * Diese Klasse stellt eine Implementierung von {@link WritableGrid} dar und
+ * basiert auf der Standard-Java Raster-Implementierung {@link WritableRaster}.
+ * Auch wenn {@link WritableRaster} prinzipell mehrere Dimensionen (Baender)
+ * zulaesst, sind die Zugriffsmethoden dieser Klasse auf ein Band beschraenkt.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class WritableGridRaster extends WritableRaster implements WritableGrid {
+  /**
+   * Die Dimension des Rasters (2).
+   */
+  public static final int RASTER_DIM = 2;
+
+  private static final int band = 0;
+
+  /**
+   * Speichert die Geo-Referenz (Longitude, Latitude, Breite, Hoehe) des
+   * Rasters.
+   */
+  protected Rectangle2D envelope;
+
+  /**
+   * Speichert das CRS des Rasters. Default ist WGS84.
+   */
+  protected CoordinateReferenceSystem crs = GTUtil.WGS84;
+
+  /**
+   * Erzeugt ein georeferenziertes Raster aus einem nicht-georeferenzierten.
+   * @param raster   Datenbasis fuer das Raster
+   * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
+   * @param crs      CoordinateReferenceSystem des Rasters
+   * @see DataBuffer
+   */
+  public WritableGridRaster(WritableRaster raster, Rectangle2D envelope, CoordinateReferenceSystem crs) {
+    super( new ComponentSampleModel(raster.getDataBuffer().getDataType(),
+                                    raster.getWidth(),
+                                    raster.getHeight(),
+                                    1,
+                                    raster.getWidth(),
+                                    new int[] {0}),
+           raster.getDataBuffer(),
+           new Point(raster.getMinX(), raster.getMinY())
+    );
+    this.envelope = envelope;
+    this.crs      = ( crs == null ) ? GTUtil.WGS84 : crs;
+  }
+
+  /**
+   * Erzeugt ein georeferenziertes Raster aus einem nicht-georeferenzierten.
+   * Als CRS wird WGS84 verwendet.
+   * @param raster   Datenbasis fuer das Raster
+   * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
+   * @see DataBuffer
+   */
+  public WritableGridRaster(WritableRaster raster, Rectangle2D envelope) {
+    this(raster,envelope,null);
+  }
+
+  /**
+   * Erzeugt ein neues Raster.
+   * @param dataType Im Raster zu speichernder Datentyp (siehe {@link DataBuffer})
+   * @param minX Raster-Index der ersten Zelle in X-Richtung
+   * @param minY Raster-Index der ersten Zelle in Y-Richtung
+   * @param rasterWidth Breite des Rasters (in Zellen)
+   * @param rasterHeight Hoehe des Rasters (in Zellen)
+   * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
+   * @param crs CoordinateReferenceSystem des Rasters
+   * @see DataBuffer
+   */
+  public WritableGridRaster(int dataType, int minX, int minY, int rasterWidth, int rasterHeight, Rectangle2D envelope, CoordinateReferenceSystem crs) {
+    super( new ComponentSampleModel(dataType,
+                                    rasterWidth,
+                                    rasterHeight,
+                                    1,
+                                    rasterWidth,
+                                    new int[] {0}),
+           new Point(minX,minY)
+    );
+    this.envelope = envelope;
+    this.crs      = ( crs == null ) ? GTUtil.WGS84 : crs;
+  }
+
+  /**
+   * Erzeugt ein neues Raster in WGS84.
+   * @param dataType Im Raster zu speichernder Datentyp (siehe {@link DataBuffer})
+   * @param minX Raster-Index der ersten Zelle in X-Richtung
+   * @param minY Raster-Index der ersten Zelle in Y-Richtung
+   * @param rasterWidth Breite des Rasters (in Zellen)
+   * @param rasterHeight Hoehe des Rasters (in Zellen)
+   * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
+   * @see DataBuffer
+   */
+  public WritableGridRaster(int dataType, int minX, int minY, int rasterWidth, int rasterHeight, Rectangle2D envelope) {
+    this(dataType,minX,minY,rasterWidth,rasterHeight,envelope,null);
+  }
+
+  /**
+   * Erzeugt ein neues Raster.
+   * @param dataType Im Raster zu speichernder Datentyp (siehe {@link DataBuffer})
+   * @param minX Raster-Index der ersten Zelle in X-Richtung
+   * @param minY Raster-Index der ersten Zelle in Y-Richtung
+   * @param rasterWidth Breite des Rasters (in Zellen)
+   * @param rasterHeight Hoehe des Rasters (in Zellen)
+   * @param lon Georeferenz (Longitude = X-Koordinate)
+   * @param lat Georeferenz (Latitude = Y-Koordinate)
+   * @param realWidth Breite des Rasters (in Metern)
+   * @param realHeight Hoehe des Rasters (in Metern)
+   * @param crs CoordinateReferenceSystem des Rasters
+   * @see DataBuffer
+   */
+  public WritableGridRaster(int dataType, int minX, int minY, int rasterWidth, int rasterHeight, double lon, double lat, double realWidth, double realHeight, CoordinateReferenceSystem crs) {
+    this( dataType, minX, minY, rasterWidth, rasterHeight, new Rectangle2D.Double(lon,lat,realWidth,realHeight), crs );
+  }
+
+  /**
+   * Erzeugt ein neues Raster.
+   * @param dataType Im Raster zu speichernder Datentyp (siehe {@link DataBuffer})
+   * @param rasterWidth Breite des Rasters (in Zellen)
+   * @param rasterHeight Hoehe des Rasters (in Zellen)
+   * @param lon Georeferenz (Longitude = X-Koordinate)
+   * @param lat Georeferenz (Latitude = Y-Koordinate)
+   * @param realWidth Breite des Rasters (in Metern)
+   * @param realHeight Hoehe des Rasters (in Metern)
+   * @param crs CoordinateReferenceSystem des Rasters
+   * @see DataBuffer
+   */
+  public WritableGridRaster(int dataType, int rasterWidth, int rasterHeight, double lon, double lat, double realWidth, double realHeight, CoordinateReferenceSystem crs) {
+    this(dataType,0,0,rasterWidth,rasterHeight,lon,lat,realWidth,realHeight,crs);
+  }
+
+  /**
+   * Erzeugt ein neues Raster.
+   * @param dataType Im Raster zu speichernder Datentyp (siehe {@link DataBuffer})
+   * @param rasterWidth Breite des Rasters (in Zellen)
+   * @param rasterHeight Hoehe des Rasters (in Zellen)
+   * @param envelope Georeferenz des Rasters (Longitude = X-Koordinate, Latitude = Y-Koordinate, Breite und Hoehe des Rasters in Metern)
+   * @param crs CoordinateReferenceSystem des Rasters
+   * @see DataBuffer
+   */
+  public WritableGridRaster(int dataType, int rasterWidth, int rasterHeight, Rectangle2D envelope, CoordinateReferenceSystem crs) {
+    this(dataType,0,0,rasterWidth,rasterHeight,envelope,crs);
+  }
+
+  /**
+   * Macht zur Zeit noch nichts.
+   * @todo WritableGridRaster.dispose() implementieren
+   */
+  public void dispose() {
+  }
+
+  /**
+   * Liefert das {@link CoordinateReferenceSystem} in dem das Raster
+   * dargestellt ist.
+   */
+  public CoordinateReferenceSystem getCoordinateReferenceSystem() {
+    return this.crs;
+  }
+
+  /**
+   * Liefert die X-Koordinate der Georeferenz (Longitude) der linken unteren
+   * Ecke des Rasters (Südwest).
+   * ((offtopic: Südwest ist das Gegenteil von Nördost))
+   */
+  public double getX() {
+    return envelope.getX();
+  }
+
+  /**
+   * Liefert die Y-Koordinate der Georeferenz (Latitude) der linken unteren
+   * Ecke des Rasters (Südwest).
+   */
+  public double getY() {
+    return envelope.getY();
+  }
+
+  /**
+   * Liefert die reale Breite des Rasters.
+   */
+  public double getRealWidth() {
+    return envelope.getWidth();
+  }
+
+  /**
+   * Liefert die reale Breite des Rasters.
+   */
+  public double getRealHeight() {
+    return envelope.getHeight();
+  }
+
+  /**
+   * Liefert die Georeferenz (Lat/Lon) und Ausdehnung des Rasters.
+   */
+  public Rectangle2D getEnvelope() {
+    return (Rectangle2D)envelope.clone();
+  }
+
+  /**
+   * Liefert die reale Breite einer Rasterzelle.
+   * @return <code>getRealWidth() / getWidth()</code>
+   */
+  public double getCellWidth() {
+    return getRealWidth() / getWidth();
+  }
+
+  /**
+   * Liefert die reale Breite einer Rasterzelle.
+   * @return <code>getRealHeight() / getHeight()</code>
+   */
+  public double getCellHeight() {
+    return getRealHeight() / getHeight();
+  }
+
+  /**
+   * Liefert die Art der Daten, die im Raster gespeichert werden koennen. Diese
+   * wird durch eine der TYPE-Konstanten in {@link DataBuffer}
+   * repraesentiert.
+   */
+  public int getSampleType() {
+    return getDataBuffer().getDataType();
+  }
+
+  /**
+   * Setzt einen Wert im Raster ueber Raster-Koordinaten.
+   * @param value neuer Wert
+   * @param cell  2D-Raster-Koordinate (Zellenindizes, beginnend bei
+   *              {@link #getMinX()} und {@link #getMinY()})
+   * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
+   *            Koordinaten angegeben werden
+   */
+  public void setRasterSample(Object value, int... cell) {
+    if ( cell.length < RASTER_DIM )
+      throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
+//    // Bei 'raster' (WritableRaster) beginnen die Raster-Koordinaten in der
+//    // linken oberen Ecke. Im Grid soll die Zaehlung jedoch in der linken unteren
+//    // Ecke beginnen -> Y-Koordinate umrechnen
+//    int x = cell[0];
+//    int y = getMinY() + getHeight()-1 - cell[1];
+    // Bei 'raster' (WritableRaster) beginnen die Raster-Koordinaten in der
+    // linken oberen Ecke. Im Grid soll es genauso sein!!
+    int x = cell[0];
+    int y = cell[1];
+
+    switch ( getSampleType() ) {
+      case DataBuffer.TYPE_BYTE:
+      case DataBuffer.TYPE_SHORT:
+      case DataBuffer.TYPE_USHORT:
+      case DataBuffer.TYPE_INT: setSample(x,y,band,((Number)value).intValue());
+                                break;
+      case DataBuffer.TYPE_FLOAT: setSample(x,y,band,((Number)value).floatValue());
+                                  break;
+      case DataBuffer.TYPE_DOUBLE: setSample(x,y,band,((Number)value).doubleValue());
+                                   break;
+    }
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
+   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+   *             {@link #getMinX()} und {@link #getMinY()})
+   * @return je nach {@linkplain #getSampleType() Art} des Rasters einen
+   *         <code>int</code>, <code>float</code> oder <code>double</code>
+   * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
+   *            Koordinaten angegeben werden
+   */
+  public Object getRasterSample(int... cell) {
+    if ( cell.length < RASTER_DIM )
+      throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
+//    // Bei 'raster' (WritableRaster) beginnen die Raster-Koordinaten in der
+//    // linken oberen Ecke. Im Grid soll die Zaehlung jedoch in der linken unteren
+//    // Ecke beginnen -> Y-Koordinate umrechnen
+//    int x = cell[0];
+//    int y = getMinY() + getHeight()-1 - cell[1];
+    // Bei 'raster' (WritableRaster) beginnen die Raster-Koordinaten in der
+    // linken oberen Ecke. Im Grid soll es genauso sein!!
+    int x = cell[0];
+    int y = cell[1];
+    switch ( getSampleType() ) {
+      case DataBuffer.TYPE_BYTE:
+      case DataBuffer.TYPE_SHORT:
+      case DataBuffer.TYPE_USHORT:
+      case DataBuffer.TYPE_INT: return getSample(x,y,band);
+      case DataBuffer.TYPE_FLOAT: return getSampleFloat(x,y,band);
+      case DataBuffer.TYPE_DOUBLE: return getSampleDouble(x,y,band);
+    }
+    return getSample(x,y,band);
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
+   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+   *             {@link #getMinX()} und {@link #getMinY()})
+   */
+  public short getRasterSampleAsShort(int... cell) {
+    return ((Number)getRasterSample(cell)).shortValue();
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
+   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+   *             {@link #getMinX()} und {@link #getMinY()})
+   */
+  public byte getRasterSampleAsByte(int... cell) {
+    return ((Number)getRasterSample(cell)).byteValue();
+  }
+
+
+  /**
+   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
+   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+   *             {@link #getMinX()} und {@link #getMinY()})
+   */
+  public int getRasterSampleAsInt(int... cell) {
+    return ((Number)getRasterSample(cell)).intValue();
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
+   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+   *             {@link #getMinX()} und {@link #getMinY()})
+   */
+  public long getRasterSampleAsLong(int... cell) {
+    return ((Number)getRasterSample(cell)).longValue();
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
+   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+   *             {@link #getMinX()} und {@link #getMinY()})
+   */
+  public float getRasterSampleAsFloat(int... cell) {
+    return ((Number)getRasterSample(cell)).floatValue();
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
+   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+   *             {@link #getMinX()} und {@link #getMinY()})
+   */
+  public double getRasterSampleAsDouble(int... cell) {
+    return ((Number)getRasterSample(cell)).doubleValue();
+  }
+
+  /**
+   * Setzt einen Wert des Rasters ueber Geo-Koordinaten. Liegt der
+   * Koordinatenwert genau auf der Grenze zwischen zwei Rasterzellen, wird die
+   * naechst groessere Zelle gewaehlt (ausser die Grenze entspricht dem Raster-Rand!).
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
+   *            Koordinaten angegeben werden
+   */
+  public void setGridSample(Object value, double... coord) {
+    if ( coord.length < RASTER_DIM )
+      throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
+    // Koordinaten umrechnen in Zellen-Index
+    int cellX = convertRealToRaster(coord[0],0);
+    int cellY = convertRealToRaster(coord[1],1);
+    setRasterSample(value,cellX,cellY);
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
+   * Liegt der Koordinatenwert genau auf der Grenze zwischen zwei Rasterzellen,
+   * wird die naechst groessere Zelle gewaehlt (ausser die Grenze entspricht
+   * dem Raster-Rand!).
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
+   *            Koordinaten angegeben werden
+   */
+  public Object getGridSample(double... coord) {
+    if ( coord.length < RASTER_DIM )
+      throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
+    // Koordinaten umrechnen in Zellen-Index
+    int cellX = convertRealToRaster(coord[0],0);
+    int cellY = convertRealToRaster(coord[1],1);
+    return getRasterSample(cellX,cellY);
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   */
+  public short getGridSampleAsShort(double... coord) {
+    return ((Number)getGridSample(coord)).shortValue();
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   */
+  public byte getGridSampleAsByte(double... coord){
+    return ((Number)getGridSample(coord)).byteValue();
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   */
+  public int getGridSampleAsInt(double... coord){
+    return ((Number)getGridSample(coord)).intValue();
+  }
+
+
+  /**
+   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   */
+  public long getGridSampleAsLong(double... coord){
+    return ((Number)getGridSample(coord)).longValue();
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   */
+  public float getGridSampleAsFloat(double... coord){
+    return ((Number)getGridSample(coord)).floatValue();
+  }
+
+
+  /**
+   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   */
+  public double getGridSampleAsDouble(double... coord){
+    return ((Number)getGridSample(coord)).doubleValue();
+  }
+
+  /**
+   * Konvertiert eine reale Koordinate in eine Zellennummer. Liegt der
+   * Koordinatenwert genau auf der Grenze zwischen zwei Rasterzellen, wird
+   * die naechst "groessere" Zellegewaehlt.
+   * Ausnahme bildet der Rand des Rasters. Hier wird die kleinere Zelle
+   * (also die letzte) herangezogen
+   * @param coord Georeferenz-Koordinate
+   * @param dim   Dimension, in der die Umrechnung erfolgen soll
+   * @exception UnsupportedOperationException falls eine ungueltige Dimension
+   *            angegeben wird (nur Werte 0 <= coord < {@link #RASTER_DIM} sind
+   *            zulaessig
+   */
+  public int convertRealToRaster(double coord, int dim) {
+    return AbstractWritableGrid.convertRealToRaster(this,coord,dim);
+  }
+
+  /**
+   * Konvertiert eine Zellennummer in reale Koordinate. Dabei wird die
+   * Koordinate der Zellenmitte zurueckgegeben.
+   * @param cell  Rasterzellen-Koordinate
+   * @param dim   Dimension, in der die Umrechnung erfolgen soll
+   * @exception UnsupportedOperationException falls eine ungueltige Dimension
+   *            angegeben wird (nur Werte 0 <= coord < {@link #RASTER_DIM} sind
+   *            zulaessig
+   */
+  public double convertRasterToReal(int cell, int dim) {
+    return AbstractWritableGrid.convertRasterToReal(this,cell,dim);
+  }
+
+  /**
+   * This class does not support late loading itself!
+   * @return false;
+   * @see appl.data.LateLoadable#unloadData()
+   * @see appl.data.LateLoadable#isLateLoadable()
+   */
+  public boolean isLateLoadable() {
+    return false;
+  }
+
+  /**
+   * This class  does not support late loading!
+   * @see appl.data.LateLoadable#unloadData()
+   * @see appl.data.LateLoadable#loadData()
+   */
+  public void loadData() throws LoadingException {
+  }
+
+  /**
+   * Does nothing!
+   * This class does not support late loading!
+   * @see appl.data.LateLoadable#unloadData()
+   */
+  public void unloadData() {
+  }
+
+}

Modified: trunk/src/schmitzm/data/event/AbstractObjectEvent.java
===================================================================
--- trunk/src/schmitzm/data/event/AbstractObjectEvent.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/event/AbstractObjectEvent.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,14 +1,32 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package schmitzm.data.event;
 
 /**

Modified: trunk/src/schmitzm/data/event/AbstractObjectTraceable.java
===================================================================
--- trunk/src/schmitzm/data/event/AbstractObjectTraceable.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/event/AbstractObjectTraceable.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,14 +1,32 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package schmitzm.data.event;
 
 import java.util.Vector;

Modified: trunk/src/schmitzm/data/event/GeneralObjectChangeEvent.java
===================================================================
--- trunk/src/schmitzm/data/event/GeneralObjectChangeEvent.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/event/GeneralObjectChangeEvent.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,37 +1,55 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data.event;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+/**
+ * Dieses Ereignis steht fuer eine generelle Objekt-Aenderung, welche beim
+ * Listener eine generelle Restrukturierung ausloesen sollte.
+ * {@link #getOldValue()} und {@link #getNewValue()} liefern immer <code>null</code>.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class GeneralObjectChangeEvent extends ObjectChangeEvent {
+  /**
+   * Erzeugt ein neues Ereignis.
+   * @param source Ausloesendes Objekt
+   */
+  public GeneralObjectChangeEvent(Invoker source) {
+    super(source,null,null);
+  }
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.data.event;
-
-/**
- * Dieses Ereignis steht fuer eine generelle Objekt-Aenderung, welche beim
- * Listener eine generelle Restrukturierung ausloesen sollte.
- * {@link #getOldValue()} und {@link #getNewValue()} liefern immer <code>null</code>.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class GeneralObjectChangeEvent extends ObjectChangeEvent {
-  /**
-   * Erzeugt ein neues Ereignis.
-   * @param source Ausloesendes Objekt
-   */
-  public GeneralObjectChangeEvent(Invoker source) {
-    super(source,null,null);
-  }
-
-  /**
-   * Erzeugt ein neues Ereignis.
-   * @param source Ausloesendes Objekt
-   */
-  public GeneralObjectChangeEvent(Object source) {
-    this(new Invoker(source));
-  }
-}
+  /**
+   * Erzeugt ein neues Ereignis.
+   * @param source Ausloesendes Objekt
+   */
+  public GeneralObjectChangeEvent(Object source) {
+    this(new Invoker(source));
+  }
+}

Modified: trunk/src/schmitzm/data/event/Invoker.java
===================================================================
--- trunk/src/schmitzm/data/event/Invoker.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/event/Invoker.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,14 +1,32 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package schmitzm.data.event;
 
 /**

Modified: trunk/src/schmitzm/data/event/NameChangeEvent.java
===================================================================
--- trunk/src/schmitzm/data/event/NameChangeEvent.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/event/NameChangeEvent.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,14 +1,32 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package schmitzm.data.event;
 
 /**

Modified: trunk/src/schmitzm/data/event/ObjectChangeEvent.java
===================================================================
--- trunk/src/schmitzm/data/event/ObjectChangeEvent.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/event/ObjectChangeEvent.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,14 +1,32 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package schmitzm.data.event;
 
 /**

Modified: trunk/src/schmitzm/data/event/ObjectCloseEvent.java
===================================================================
--- trunk/src/schmitzm/data/event/ObjectCloseEvent.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/event/ObjectCloseEvent.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,14 +1,32 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package schmitzm.data.event;
 
 /**

Modified: trunk/src/schmitzm/data/event/ObjectEvent.java
===================================================================
--- trunk/src/schmitzm/data/event/ObjectEvent.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/event/ObjectEvent.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,81 +1,99 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data.event;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+/**
+ * Diese Klasse stellt ein allgemeines Ereignis dar, das  von einem Objekt
+ * ausgeloest wird. Spezielle Ereignisse (z.B. "Objekt wurde geschlossen" oder
+ * "Objekt hat sich geaendert" oder "Eine Eigenschaft eines Objekts hat sich
+ * geaendert") werden durch Spezialisierungen dieser Klasse ausgedrueckt.<br>
+ * <br>
+ * Haeufig ziehen einzelne Objekt-Aenderungen andere nach sich. z.B.
+ * Wertaenderung eines Listen-Elements einer ListProperty zieht die Aenderung
+ * der Liste mit sich und somit die Aenderung des Objekts, welches
+ * die ListProperty beinhaltet. Propagiert ein Objekt eine Aenderung also weiter
+ * nach unten erzeugt es (fuer seine Listener) ein neues Event:<br>
+ * <blockquote><pre>
+ * ...
+ * public void performObjectEvent(ObjectEvent e) {
+ *     if ( e instanceof ObjectChangeEvent ) {
+ *         ObjectChangeEvent oce = (ObjectChangeEvent)e;
+ *         fireEvent( new ObjectChangeEvent(
+ *             new Invoker( this,oce.getSource() ),
+ *             oce.getOldValue(),
+ *             oce.getNewValue()
+ *         ) );
+ *     }
+ * }
+ * ...
+ * </pre></blockquote>
+ * Aus diesem Grund ist <code>ObjectEvent.getObject()</code> nicht immer das
+ * Element, welches die Aenderung ausgeloest hat. Diese kann jedoch durch
+ * <code>source.getRoot()</code> ermittelt werden.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public interface ObjectEvent {
+  /**
+   * Liefert die ID des Events. Mit dieser koennen Unterereignisse differenziert
+   * werden (z.B. "Objekt hinzugefuegt", oder "Objekt entfernt" fuer Datenpool-Event)
+   */
+  public int getType();
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+  /**
+   * Liefert die Objekt-Hierarchie, die von dem Ereignis betroffen ist.
+   * Deren Wurzel ist das Objekt, welches das Ereignis ausgeloest hat.<br>
+   * <b>Beispiel:</b><br>
+   * <ul>
+   * <li><code>getInvoker().getObject()</code> stellt das "letzte" von einer
+   *     Datenaenderung betroffene Objekt dar<br>
+   *     z.B. ein <code>XuluObject</code></li>
+   * <li><code>getInvoker().getInvoker().getObject()</code> stellt das
+   *     "darueberliegende" Objekt dar<br>
+   *     z.B. eine <code>ListProperty</code> des <code>XuluObject</code></li>
+   * <li><code>getInvoker().getRoot()</code> liefert das Objekt, was sich
+   *     urspruenglich geaendert und somit das Event ausgeloest hat ("die Wurzel")<br>
+   *     z.B. ein Element der <code>ListProperty</code> des <code>XuluObject</code></li>
+   * </ul>
+   * @see schmitzm.data.event.Invoker
+   */
+  public Invoker getSource();
 
-package schmitzm.data.event;
-
-/**
- * Diese Klasse stellt ein allgemeines Ereignis dar, das  von einem Objekt
- * ausgeloest wird. Spezielle Ereignisse (z.B. "Objekt wurde geschlossen" oder
- * "Objekt hat sich geaendert" oder "Eine Eigenschaft eines Objekts hat sich
- * geaendert") werden durch Spezialisierungen dieser Klasse ausgedrueckt.<br>
- * <br>
- * Haeufig ziehen einzelne Objekt-Aenderungen andere nach sich. z.B.
- * Wertaenderung eines Listen-Elements einer ListProperty zieht die Aenderung
- * der Liste mit sich und somit die Aenderung des Objekts, welches
- * die ListProperty beinhaltet. Propagiert ein Objekt eine Aenderung also weiter
- * nach unten erzeugt es (fuer seine Listener) ein neues Event:<br>
- * <blockquote><pre>
- * ...
- * public void performObjectEvent(ObjectEvent e) {
- *     if ( e instanceof ObjectChangeEvent ) {
- *         ObjectChangeEvent oce = (ObjectChangeEvent)e;
- *         fireEvent( new ObjectChangeEvent(
- *             new Invoker( this,oce.getSource() ),
- *             oce.getOldValue(),
- *             oce.getNewValue()
- *         ) );
- *     }
- * }
- * ...
- * </pre></blockquote>
- * Aus diesem Grund ist <code>ObjectEvent.getObject()</code> nicht immer das
- * Element, welches die Aenderung ausgeloest hat. Diese kann jedoch durch
- * <code>source.getRoot()</code> ermittelt werden.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public interface ObjectEvent {
-  /**
-   * Liefert die ID des Events. Mit dieser koennen Unterereignisse differenziert
-   * werden (z.B. "Objekt hinzugefuegt", oder "Objekt entfernt" fuer Datenpool-Event)
-   */
-  public int getType();
-
-  /**
-   * Liefert die Objekt-Hierarchie, die von dem Ereignis betroffen ist.
-   * Deren Wurzel ist das Objekt, welches das Ereignis ausgeloest hat.<br>
-   * <b>Beispiel:</b><br>
-   * <ul>
-   * <li><code>getInvoker().getObject()</code> stellt das "letzte" von einer
-   *     Datenaenderung betroffene Objekt dar<br>
-   *     z.B. ein <code>XuluObject</code></li>
-   * <li><code>getInvoker().getInvoker().getObject()</code> stellt das
-   *     "darueberliegende" Objekt dar<br>
-   *     z.B. eine <code>ListProperty</code> des <code>XuluObject</code></li>
-   * <li><code>getInvoker().getRoot()</code> liefert das Objekt, was sich
-   *     urspruenglich geaendert und somit das Event ausgeloest hat ("die Wurzel")<br>
-   *     z.B. ein Element der <code>ListProperty</code> des <code>XuluObject</code></li>
-   * </ul>
-   * @see schmitzm.data.event.Invoker
-   */
-  public Invoker getSource();
-
-  /**
-   * Erweitert die Objekt-Hierarchie, die von dem Ereignis betroffen ist.
-   * Das Objekt wird dabei der Hierarchie vorangestellt. Im folgenden ist es
-   * ueber <code>getInvoker().getObject()</code> referenzierbar. Das bisher
-   * ueber diesen Aufruf referenzierte Objekt erhaelt man dann ueber
-   * <code>getInvoker().getInvoker().getObject()</code>.
-   * @param object neues betroffenes Objekt
-   */
-  public void expandSource(Object object);
-
-}
+  /**
+   * Erweitert die Objekt-Hierarchie, die von dem Ereignis betroffen ist.
+   * Das Objekt wird dabei der Hierarchie vorangestellt. Im folgenden ist es
+   * ueber <code>getInvoker().getObject()</code> referenzierbar. Das bisher
+   * ueber diesen Aufruf referenzierte Objekt erhaelt man dann ueber
+   * <code>getInvoker().getInvoker().getObject()</code>.
+   * @param object neues betroffenes Objekt
+   */
+  public void expandSource(Object object);
+
+}

Modified: trunk/src/schmitzm/data/event/ObjectListener.java
===================================================================
--- trunk/src/schmitzm/data/event/ObjectListener.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/event/ObjectListener.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,14 +1,32 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package schmitzm.data.event;
 
 /**

Modified: trunk/src/schmitzm/data/event/ObjectTraceable.java
===================================================================
--- trunk/src/schmitzm/data/event/ObjectTraceable.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/event/ObjectTraceable.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,14 +1,32 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package schmitzm.data.event;
 
 /**

Modified: trunk/src/schmitzm/data/property/Access.java
===================================================================
--- trunk/src/schmitzm/data/property/Access.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/property/Access.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,162 +1,180 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data.property;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+/**
+ * Diese Klasse stellt ein allgemeines Zugriffsrecht fuer eine Eigenschaft
+ * ({@link Property Property}) dar. Dieses dient dazu, nur bestimmten Zugriff auf
+ * das jeweilige Objekt zu erlauben (z.B. nur Lesezugriff). Aus diesem
+ * Grund gibt es auch keine <code>getObject()</code>-Methode, ueber welche ein
+ * direkter (kompletter) Zugriff auf das Objekt moeglich waere.<br>
+ * Welche und vor allem wie viele (gleichzeitige) Zugriffsrechte ein Objekt
+ * erlaubt, wird von der jeweiligen Objektklasse selbst definiert.<br>
+ * Ein Zugriffsrecht kann vom Besitzer zurueckgegeben werden
+ * ({@link #release() release()}) oder auch von einem globaler Rechteverwalter
+ * entzogen werden ({@link #dispose() dispose()}).
+ * In beiden Faellen sollen saemtliche folgenden Zugriffsmethoden auf
+ * das Objekt mit Exceptions abgebrochen werden.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public abstract class Access {
+  /** Speichert den Besitzer des Zugriffsrechts */
+  protected Object     owner  = null;
+  /** Speichert das Objekt, ueber das das Zugriffsrecht ausgesprochen wurde. */
+  protected Accessible object = null;
+  /** Gibt an, ob das Recht noch gueltig ist */
+  protected boolean    disposed = false;
+  /** Diese Konstante steht fuer unbegrenzte Anzahl an Zugriffen auf das Recht */
+  public static final int UNLIMITED_ACCESSTIMES = -1;
+  /** Speichert, wie of ein Objekt das Zugrifsrecht bereits benutzt hat. */
+  protected int        accessTimes = 0;
+  /** Speichert, wie of ein Objekt das Zugrifsrecht nutzen darf. */
+  protected int        maxAccessTimes = UNLIMITED_ACCESSTIMES;
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+  /**
+   * Erzeugt ein neues Zugriffsrecht.
+   * @param object Objekt auf das sich das Recht bezieht
+   * @param owner  Besitzer des Rechts
+   * @param maxAccessTimes Anzahl an (Methoden-)Zugriffen, die der Rechtebesitzer
+   *                       taetigen darf, bevor das Recht automatisch entzogen wird
+   */
+  public Access(Accessible object, Object owner, int maxAccessTimes) {
+    this.object         = object;
+    this.owner          = owner;
+    this.maxAccessTimes = maxAccessTimes;
+    this.object.applyAccess(this);
+  }
 
-package schmitzm.data.property;
-
-/**
- * Diese Klasse stellt ein allgemeines Zugriffsrecht fuer eine Eigenschaft
- * ({@link Property Property}) dar. Dieses dient dazu, nur bestimmten Zugriff auf
- * das jeweilige Objekt zu erlauben (z.B. nur Lesezugriff). Aus diesem
- * Grund gibt es auch keine <code>getObject()</code>-Methode, ueber welche ein
- * direkter (kompletter) Zugriff auf das Objekt moeglich waere.<br>
- * Welche und vor allem wie viele (gleichzeitige) Zugriffsrechte ein Objekt
- * erlaubt, wird von der jeweiligen Objektklasse selbst definiert.<br>
- * Ein Zugriffsrecht kann vom Besitzer zurueckgegeben werden
- * ({@link #release() release()}) oder auch von einem globaler Rechteverwalter
- * entzogen werden ({@link #dispose() dispose()}).
- * In beiden Faellen sollen saemtliche folgenden Zugriffsmethoden auf
- * das Objekt mit Exceptions abgebrochen werden.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public abstract class Access {
-  /** Speichert den Besitzer des Zugriffsrechts */
-  protected Object     owner  = null;
-  /** Speichert das Objekt, ueber das das Zugriffsrecht ausgesprochen wurde. */
-  protected Accessible object = null;
-  /** Gibt an, ob das Recht noch gueltig ist */
-  protected boolean    disposed = false;
-  /** Diese Konstante steht fuer unbegrenzte Anzahl an Zugriffen auf das Recht */
-  public static final int UNLIMITED_ACCESSTIMES = -1;
-  /** Speichert, wie of ein Objekt das Zugrifsrecht bereits benutzt hat. */
-  protected int        accessTimes = 0;
-  /** Speichert, wie of ein Objekt das Zugrifsrecht nutzen darf. */
-  protected int        maxAccessTimes = UNLIMITED_ACCESSTIMES;
-
-  /**
-   * Erzeugt ein neues Zugriffsrecht.
-   * @param object Objekt auf das sich das Recht bezieht
-   * @param owner  Besitzer des Rechts
-   * @param maxAccessTimes Anzahl an (Methoden-)Zugriffen, die der Rechtebesitzer
-   *                       taetigen darf, bevor das Recht automatisch entzogen wird
-   */
-  public Access(Accessible object, Object owner, int maxAccessTimes) {
-    this.object         = object;
-    this.owner          = owner;
-    this.maxAccessTimes = maxAccessTimes;
-    this.object.applyAccess(this);
-  }
-
-  /**
-   * Erzeugt ein neues Zugriffsrecht. Der Besitzer kann dieses Recht beliebig
-   * oft einsetzen.
-   * @param object Objekt auf das sich das Recht bezieht
-   * @param owner  Besitzer des Rechts
-   */
-  public Access(Accessible object, Object owner) {
-    this(object,owner,UNLIMITED_ACCESSTIMES);
-  }
-
-  /**
-   * Liefert den Besitzer des Rechts.
-   */
-  public Object getOwner() {
-    return owner;
-  }
-
-  /**
-   * Prueft, ob das Recht noch gueltig ist.
-   */
-  public boolean isDisposed() {
-    return disposed;
-  }
-
-  /**
-   * Wirft eine <code>AccessViolationException</code>, wenn das Zugriffsrecht
-   * nicht mehr gueltig ist. Andernfalls passiert nichts.
-   */
-  public void checkDisposed() {
-    if ( this.isDisposed() )
-      throw new AccessViolationException(this,this.getClass().getName()+" is disposed!!");
-  }
-
-  /**
-   * Macht das Recht ungueltig. Entspricht {@link #release()}.
-   */
-  public void dispose() {
-    release();
-  }
-
-  /**
-   * Gibt das Recht auf. Das betroffene Objekt wird informiert und
-   * sollte entsprechend reagieren.<br>
-   * Alle Referenzen auf das betroffene Objekt und auf den Besitzer des
-   * Rechts werden entfernt!! {@link #getOwner()} liefert im folgenden also
-   * <code>null</code>.
-   * @see schmitzm.data.property.Accessible#releaseAccess(Access)
-   */
-  public void release() {
-    this.disposed = true;
-    if (object != null)
-      object.releaseAccess(this);
-    this.owner  = null;
-    this.object = null;
-  }
-
-  /**
-   * Vergleicht das Zugriffsrecht mit einem anderen. Zwei Rechte sind gleich,
-   * wenn:
-   * <ol>
-   * <li>Die Klassen identisch sind.</li>
-   * <li>Die Rechtebesitzer identisch sind.</li>
-   * <li>Die Rechte sich auf dasselbe Objekt beziehen.</li>
-   * </ol>
-   * @param access Ein Zugriffsrecht
-   */
-  public boolean equals(Object access) {
-    return access != null &&
-           access.getClass().equals( this.getClass() ) &&
-           ((Access)access).owner  == this.owner &&
-           ((Access)access).object == this.object;
-  }
-
-  /**
-   * Liefert die Anzahl, die der Besitzer berechtigt ist, das Zugriffsrecht
-   * (ueber eine Methode) einzusetzen.
-   * @see #UNLIMITED_ACCESSTIMES
-   */
-  public int getMaxAccessTimes() {
-    return this.maxAccessTimes;
-  }
-
-  /**
-   * Liefert die Anzahl an Zugriffen, die der Besitzer bereits (ueber eine
-   * Methode) getaetigt hat.
-   */
-  public int getAccessTimes() {
-    return this.accessTimes;
-  }
-
-  /**
-   * Erhoeht die Anzahl an (Methoden-)Zugriffen auf das Recht und prueft, ob die
-   * maximal erlaubte Anzahl erreicht/ueberschritten ist.
-   * Ist dies der Fall wird das Zugriffsrecht ungueltig gemacht.
-   * @see #dispose()
-   */
-  protected void incAndCheckMaxAccessTimesReached() {
-    if ( !isDisposed() ) {
-      accessTimes++;
-      if (getMaxAccessTimes() != UNLIMITED_ACCESSTIMES &&
-          getAccessTimes() >= getMaxAccessTimes())
-        dispose();
-    }
-  }
-}
+  /**
+   * Erzeugt ein neues Zugriffsrecht. Der Besitzer kann dieses Recht beliebig
+   * oft einsetzen.
+   * @param object Objekt auf das sich das Recht bezieht
+   * @param owner  Besitzer des Rechts
+   */
+  public Access(Accessible object, Object owner) {
+    this(object,owner,UNLIMITED_ACCESSTIMES);
+  }
+
+  /**
+   * Liefert den Besitzer des Rechts.
+   */
+  public Object getOwner() {
+    return owner;
+  }
+
+  /**
+   * Prueft, ob das Recht noch gueltig ist.
+   */
+  public boolean isDisposed() {
+    return disposed;
+  }
+
+  /**
+   * Wirft eine <code>AccessViolationException</code>, wenn das Zugriffsrecht
+   * nicht mehr gueltig ist. Andernfalls passiert nichts.
+   */
+  public void checkDisposed() {
+    if ( this.isDisposed() )
+      throw new AccessViolationException(this,this.getClass().getName()+" is disposed!!");
+  }
+
+  /**
+   * Macht das Recht ungueltig. Entspricht {@link #release()}.
+   */
+  public void dispose() {
+    release();
+  }
+
+  /**
+   * Gibt das Recht auf. Das betroffene Objekt wird informiert und
+   * sollte entsprechend reagieren.<br>
+   * Alle Referenzen auf das betroffene Objekt und auf den Besitzer des
+   * Rechts werden entfernt!! {@link #getOwner()} liefert im folgenden also
+   * <code>null</code>.
+   * @see schmitzm.data.property.Accessible#releaseAccess(Access)
+   */
+  public void release() {
+    this.disposed = true;
+    if (object != null)
+      object.releaseAccess(this);
+    this.owner  = null;
+    this.object = null;
+  }
+
+  /**
+   * Vergleicht das Zugriffsrecht mit einem anderen. Zwei Rechte sind gleich,
+   * wenn:
+   * <ol>
+   * <li>Die Klassen identisch sind.</li>
+   * <li>Die Rechtebesitzer identisch sind.</li>
+   * <li>Die Rechte sich auf dasselbe Objekt beziehen.</li>
+   * </ol>
+   * @param access Ein Zugriffsrecht
+   */
+  public boolean equals(Object access) {
+    return access != null &&
+           access.getClass().equals( this.getClass() ) &&
+           ((Access)access).owner  == this.owner &&
+           ((Access)access).object == this.object;
+  }
+
+  /**
+   * Liefert die Anzahl, die der Besitzer berechtigt ist, das Zugriffsrecht
+   * (ueber eine Methode) einzusetzen.
+   * @see #UNLIMITED_ACCESSTIMES
+   */
+  public int getMaxAccessTimes() {
+    return this.maxAccessTimes;
+  }
+
+  /**
+   * Liefert die Anzahl an Zugriffen, die der Besitzer bereits (ueber eine
+   * Methode) getaetigt hat.
+   */
+  public int getAccessTimes() {
+    return this.accessTimes;
+  }
+
+  /**
+   * Erhoeht die Anzahl an (Methoden-)Zugriffen auf das Recht und prueft, ob die
+   * maximal erlaubte Anzahl erreicht/ueberschritten ist.
+   * Ist dies der Fall wird das Zugriffsrecht ungueltig gemacht.
+   * @see #dispose()
+   */
+  protected void incAndCheckMaxAccessTimesReached() {
+    if ( !isDisposed() ) {
+      accessTimes++;
+      if (getMaxAccessTimes() != UNLIMITED_ACCESSTIMES &&
+          getAccessTimes() >= getMaxAccessTimes())
+        dispose();
+    }
+  }
+}

Modified: trunk/src/schmitzm/data/property/AccessViolationException.java
===================================================================
--- trunk/src/schmitzm/data/property/AccessViolationException.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/property/AccessViolationException.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,50 +1,68 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data.property;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+/**
+ * Diese Exception wird immer dann geworfen, wenn ein Fehler mit Zugriffsrechten
+ * auftritt.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class AccessViolationException extends RuntimeException {
+  private Access access = null;
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+  /**
+   * Erzeugt einen neuen Fehler.
+   * @param a       betroffener Zugriff
+   * @param message Fehlermeldung
+   */
+  public AccessViolationException(Access a, String message) {
+    super(message);
+    // original : this.access = access;
+    this.access = a; // changed by SK
 
-package schmitzm.data.property;
-
-/**
- * Diese Exception wird immer dann geworfen, wenn ein Fehler mit Zugriffsrechten
- * auftritt.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class AccessViolationException extends RuntimeException {
-  private Access access = null;
-
-  /**
-   * Erzeugt einen neuen Fehler.
-   * @param a       betroffener Zugriff
-   * @param message Fehlermeldung
-   */
-  public AccessViolationException(Access a, String message) {
-    super(message);
-    // original : this.access = access;
-    this.access = a; // changed by SK
-
-  }
-
-  /**
-   * Erzeugt einen neuen Fehler.
-   * @param a       betroffener Zugriff
-   */
-  public AccessViolationException(Access a) {
-    this(a,"");
-  }
-
-  /**
-   * Liefert das Zugriffsrecht, bei dem der Fehler aufgetreten ist.
-   */
-  public Access getAccess() {
-    return access;
-  }
-
-}
+  }
+
+  /**
+   * Erzeugt einen neuen Fehler.
+   * @param a       betroffener Zugriff
+   */
+  public AccessViolationException(Access a) {
+    this(a,"");
+  }
+
+  /**
+   * Liefert das Zugriffsrecht, bei dem der Fehler aufgetreten ist.
+   */
+  public Access getAccess() {
+    return access;
+  }
+
+}

Modified: trunk/src/schmitzm/data/property/Accessible.java
===================================================================
--- trunk/src/schmitzm/data/property/Accessible.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/property/Accessible.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,63 +1,81 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data.property;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+/**
+ * Dieses Interface ist von allen Objektklassen zu implementieren, fuer die
+ * besondere Zugriffsrechte erteilt werden sollen.
+ * @see schmitzm.data.property.Access
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public interface Accessible {
+  /**
+   * Wird aufgerufen, wenn ein Zugriffsrecht von einem Objekt wieder freigegen
+   * wird oder das Zugriffsrecht entzogen wurde.
+   * @param access erzeugtes Zugriffsrecht
+   */
+  public void releaseAccess(Access access);
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+  /**
+   * Wird aufgerufen, wenn ein Zugriffsrecht fuer das Objekt erzeugt wird.
+   * @param access erzeugtes Zugriffsrecht
+   */
+  public void applyAccess(Access access);
 
-package schmitzm.data.property;
-
-/**
- * Dieses Interface ist von allen Objektklassen zu implementieren, fuer die
- * besondere Zugriffsrechte erteilt werden sollen.
- * @see schmitzm.data.property.Access
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public interface Accessible {
-  /**
-   * Wird aufgerufen, wenn ein Zugriffsrecht von einem Objekt wieder freigegen
-   * wird oder das Zugriffsrecht entzogen wurde.
-   * @param access erzeugtes Zugriffsrecht
-   */
-  public void releaseAccess(Access access);
-
-  /**
-   * Wird aufgerufen, wenn ein Zugriffsrecht fuer das Objekt erzeugt wird.
-   * @param access erzeugtes Zugriffsrecht
-   */
-  public void applyAccess(Access access);
-
-  /**
-   * Entzieht saemtlichen Zugriffsrechten, die aktuell fuer das Objekt
-   * verteilt sind, die Gueltigkeit.
-   */
-  public void disposeAllAccess();
-
-  /**
-   * Liefert die Anzahl an Zugriffsrechten einer bestimmten Art, die aktuell
-   * fuer das Objekt verteilt sind.
-   */
-  public int getAccessCount(Class c);
-
-  /**
-   * Prueft, ob aktuell Zugriffsrechte einer bestimmten Art
-   * auf das Objekt verteilt sind.
-   */
-  public boolean hasAccess(Class c);
-
-  /**
-   * Liefert die Anzahl an Zugriffsrechten, die aktuell fuer das Objekt verteilt
-   * sind.
-   */
-  public int getAccessCount();
-
-  /**
-   * Prueft, ob aktuell Zugriffsrechte auf das Objekt verteilt sind.
-   */
-  public boolean hasAccess();
-}
+  /**
+   * Entzieht saemtlichen Zugriffsrechten, die aktuell fuer das Objekt
+   * verteilt sind, die Gueltigkeit.
+   */
+  public void disposeAllAccess();
+
+  /**
+   * Liefert die Anzahl an Zugriffsrechten einer bestimmten Art, die aktuell
+   * fuer das Objekt verteilt sind.
+   */
+  public int getAccessCount(Class c);
+
+  /**
+   * Prueft, ob aktuell Zugriffsrechte einer bestimmten Art
+   * auf das Objekt verteilt sind.
+   */
+  public boolean hasAccess(Class c);
+
+  /**
+   * Liefert die Anzahl an Zugriffsrechten, die aktuell fuer das Objekt verteilt
+   * sind.
+   */
+  public int getAccessCount();
+
+  /**
+   * Prueft, ob aktuell Zugriffsrechte auf das Objekt verteilt sind.
+   */
+  public boolean hasAccess();
+}

Modified: trunk/src/schmitzm/data/property/DynamicProperties.java
===================================================================
--- trunk/src/schmitzm/data/property/DynamicProperties.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/property/DynamicProperties.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,69 +1,87 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data.property;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+import schmitzm.data.event.ObjectTraceable;
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+/**
+ * Diese Interface sollten alle Objekte implementieren, die sich <b>dynamisch</b>
+ * aus einzelnen Eigenschaften ({@link Property Properties}) zusammensetzen.
+ * Die Methoden des Interface liefern sowohl den Zugriff auf die aktuellen Eigenschaften
+ * des Objekts, ermoeglichen aber auch das dynamische Hinzufuegen oder Entfernen von
+ * Eigenschaften.<br>
+ * Zu beachten ist, dass es der jeweiligen Implementierung ueberlassen ist,
+ * ob beim Entfernen einer Eigenschaft auch die komplette Eigenschaft (mittels
+ * {@link Property#dispose()}) geschlossen wird. Je nach Implementierung muss
+ * dies manuell geschehen. Deshalb liefern die remove-Methoden eine Referenz
+ * auf die entfernte Eigenschaft zurueck.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public interface DynamicProperties extends Properties, ObjectTraceable {
+  /**
+   * Fuegt dem Objekt eine Eigenschaft hinzu. Das Objekt sollte darauf
+   * achten, dass es noch keine Eigenschaft mit diesem Namen besitzt,
+   * damit die Eindeutigkeit des Names gewaehrleistet ist.
+   * @param prop Eigenschaft
+   * @exception schmitzm.data.property.PropertyException falls das
+   *            Objekt bereits eine Eigenschaft mit dem Namen der neuen
+   *            Eigenschaft besitzt
+   */
+  public void addProperty(Property prop);
 
-package schmitzm.data.property;
-
-import schmitzm.data.event.ObjectTraceable;
-
-/**
- * Diese Interface sollten alle Objekte implementieren, die sich <b>dynamisch</b>
- * aus einzelnen Eigenschaften ({@link Property Properties}) zusammensetzen.
- * Die Methoden des Interface liefern sowohl den Zugriff auf die aktuellen Eigenschaften
- * des Objekts, ermoeglichen aber auch das dynamische Hinzufuegen oder Entfernen von
- * Eigenschaften.<br>
- * Zu beachten ist, dass es der jeweiligen Implementierung ueberlassen ist,
- * ob beim Entfernen einer Eigenschaft auch die komplette Eigenschaft (mittels
- * {@link Property#dispose()}) geschlossen wird. Je nach Implementierung muss
- * dies manuell geschehen. Deshalb liefern die remove-Methoden eine Referenz
- * auf die entfernte Eigenschaft zurueck.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public interface DynamicProperties extends Properties, ObjectTraceable {
-  /**
-   * Fuegt dem Objekt eine Eigenschaft hinzu. Das Objekt sollte darauf
-   * achten, dass es noch keine Eigenschaft mit diesem Namen besitzt,
-   * damit die Eindeutigkeit des Names gewaehrleistet ist.
-   * @param prop Eigenschaft
-   * @exception schmitzm.data.property.PropertyException falls das
-   *            Objekt bereits eine Eigenschaft mit dem Namen der neuen
-   *            Eigenschaft besitzt
-   */
-  public void addProperty(Property prop);
-
-  /**
-   * Entfernt eine Eigenschaft von dem Objekt.
-   * @param name Name der Eigenschaft
-   * @return Die entferne Eigenschaft oder <code>null</code> falls das
-   *         Objekt keine Eigenschaft mit dem Namen besitzt
-   */
-  public Property removeProperty(String name);
-
-  /**
-   * Entfernt eine Eigenschaft von dem Objekt. Falls das Objekt diese
-   * Eigenschaft nicht besitzt, passiert nichts.
-   * @param prop zu entfernende Eigenschaft
-   * @return Die entferne Eigenschaft oder <code>null</code> falls das Objekt
-   *         die Eigenschaft nicht besitzt
-   */
-  public Property removeProperty(Property prop);
-
-  /**
-   * Entfernt Eigenschaften von dem Objekt. Falls das Objekt eine dieser
-   * Eigenschaften nicht besitzt, passiert fuer die entsprechende Eigenschaft
-   * nichts.
-   * @param prop zu entfernende Eigenschaft
-   * @return Die entfernten Eigenschaften (kann eine leere Eigenschaftsmenge
-   *         sein, wenn das Objekt keine der uebergebenen Eigenschaften
-   *         besitzt.
-   */
-  public Properties removeProperties(Properties prop);
-}
+  /**
+   * Entfernt eine Eigenschaft von dem Objekt.
+   * @param name Name der Eigenschaft
+   * @return Die entferne Eigenschaft oder <code>null</code> falls das
+   *         Objekt keine Eigenschaft mit dem Namen besitzt
+   */
+  public Property removeProperty(String name);
+
+  /**
+   * Entfernt eine Eigenschaft von dem Objekt. Falls das Objekt diese
+   * Eigenschaft nicht besitzt, passiert nichts.
+   * @param prop zu entfernende Eigenschaft
+   * @return Die entferne Eigenschaft oder <code>null</code> falls das Objekt
+   *         die Eigenschaft nicht besitzt
+   */
+  public Property removeProperty(Property prop);
+
+  /**
+   * Entfernt Eigenschaften von dem Objekt. Falls das Objekt eine dieser
+   * Eigenschaften nicht besitzt, passiert fuer die entsprechende Eigenschaft
+   * nichts.
+   * @param prop zu entfernende Eigenschaft
+   * @return Die entfernten Eigenschaften (kann eine leere Eigenschaftsmenge
+   *         sein, wenn das Objekt keine der uebergebenen Eigenschaften
+   *         besitzt.
+   */
+  public Properties removeProperties(Properties prop);
+}

Modified: trunk/src/schmitzm/data/property/ListProperty.java
===================================================================
--- trunk/src/schmitzm/data/property/ListProperty.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/property/ListProperty.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,14 +1,32 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package schmitzm.data.property;
 
 import java.util.Vector;

Modified: trunk/src/schmitzm/data/property/ListPropertyReadAccess.java
===================================================================
--- trunk/src/schmitzm/data/property/ListPropertyReadAccess.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/property/ListPropertyReadAccess.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,96 +1,114 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data.property;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+/**
+ * Diese Klasse stellt ein Recht auf Lesezugriff fuer eine
+ * {@link ListProperty} dar. Da Listen dynamisch aufgebaut sind, erweitert sie
+ * hierzu den {@link PropertyReadAccess} um <code>getCount</code>-
+ * und <code>indexOf</code>-Methoden.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class ListPropertyReadAccess extends PropertyReadAccess {
+  /**
+   * Erzeugt ein neues Lesezugriffsrecht fuer Listen. Die Anzahl an Zugriffen
+   * fuer den Besitzer ist unbegrenzt.
+   * @param object Instanz von <code>ListProperty</code> auf die sich das Recht bezieht
+   * @param owner  Besitzer des Rechts
+   * @see schmitzm.data.property.ListProperty
+   * @exception schmitzm.data.property.AccessViolationException falls das
+   *            angegebene Objekt <b>keine</b> <code>ListProperty</code> ist
+   */
+  public ListPropertyReadAccess(Accessible object, Object owner) {
+    this(object, owner, UNLIMITED_ACCESSTIMES);
+  }
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+  /**
+   * Erzeugt ein neues Lesezugriffsrecht fuer Listen.
+   * @param object Instanz von <code>ListProperty</code> auf die sich das Recht bezieht
+   * @param owner  Besitzer des Rechts
+   * @param maxAccessTimes Anzahl an (Methoden-)Zugriffen, die der Rechtebesitzer
+   *                       taetigen darf, bevor das Recht automatisch entzogen wird
+   * @see schmitzm.data.property.ListProperty
+   * @exception schmitzm.data.property.AccessViolationException falls das
+   *            angegebene Objekt <b>keine</b> <code>ListProperty</code> ist
+   */
+  public ListPropertyReadAccess(Accessible object, Object owner, int maxAccessTimes) {
+    super(object, owner, maxAccessTimes);
+    if (! (object instanceof ListProperty))
+      throw new AccessViolationException(this,this.getClass().getName() +" can only be instantiated for ListProperties");
+  }
 
-package schmitzm.data.property;
-
-/**
- * Diese Klasse stellt ein Recht auf Lesezugriff fuer eine
- * {@link ListProperty} dar. Da Listen dynamisch aufgebaut sind, erweitert sie
- * hierzu den {@link PropertyReadAccess} um <code>getCount</code>-
- * und <code>indexOf</code>-Methoden.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class ListPropertyReadAccess extends PropertyReadAccess {
-  /**
-   * Erzeugt ein neues Lesezugriffsrecht fuer Listen. Die Anzahl an Zugriffen
-   * fuer den Besitzer ist unbegrenzt.
-   * @param object Instanz von <code>ListProperty</code> auf die sich das Recht bezieht
-   * @param owner  Besitzer des Rechts
-   * @see schmitzm.data.property.ListProperty
-   * @exception schmitzm.data.property.AccessViolationException falls das
-   *            angegebene Objekt <b>keine</b> <code>ListProperty</code> ist
-   */
-  public ListPropertyReadAccess(Accessible object, Object owner) {
-    this(object, owner, UNLIMITED_ACCESSTIMES);
-  }
-
-  /**
-   * Erzeugt ein neues Lesezugriffsrecht fuer Listen.
-   * @param object Instanz von <code>ListProperty</code> auf die sich das Recht bezieht
-   * @param owner  Besitzer des Rechts
-   * @param maxAccessTimes Anzahl an (Methoden-)Zugriffen, die der Rechtebesitzer
-   *                       taetigen darf, bevor das Recht automatisch entzogen wird
-   * @see schmitzm.data.property.ListProperty
-   * @exception schmitzm.data.property.AccessViolationException falls das
-   *            angegebene Objekt <b>keine</b> <code>ListProperty</code> ist
-   */
-  public ListPropertyReadAccess(Accessible object, Object owner, int maxAccessTimes) {
-    super(object, owner, maxAccessTimes);
-    if (! (object instanceof ListProperty))
-      throw new AccessViolationException(this,this.getClass().getName() +" can only be instantiated for ListProperties");
-  }
-
-  /**
-   * Liefert die aktuelle Anzahl an Elementen, die in der Liste gespeichert
-   * sind.
-   * @exception schmitzm.data.property.AccessViolationException falls
-   *            das Leserecht auf der Property nicht mehr gueltig ist
-   */
-  public int getCount() {
-    checkDisposed();
-    int ret = ((ListProperty)object).getCount();
-    incAndCheckMaxAccessTimesReached();
-    return ret;
-  }
-
-  /**
-   * Checkt, ob die Liste leer ist.
-   * @exception schmitzm.data.property.AccessViolationException falls
-   *            das Leserecht auf der Property nicht mehr gueltig ist
-   */
-  public boolean isEmpty() {
-    return getCount() == 0;
-  }
-
-  /**
-   * Liefert den Listen-Index des ersten Vorkommens eines Elements.
-   * @param value Listen-Element
-   * @return -1 falls das Element nicht in der Liste vorhanden ist.
-   * @exception schmitzm.data.property.AccessViolationException falls
-   *            das Leserecht auf der Property nicht mehr gueltig ist
-   */
-  public int indexOf(Object value) {
-    checkDisposed();
-    int ret = ((ListProperty)object).indexOf(value);
-    incAndCheckMaxAccessTimesReached();
-    return ret;
-  }
-
-  /**
-   * Checkt, ob ein Objekt in der Liste vorhanden ist.
-   * @exception schmitzm.data.property.AccessViolationException falls
-   *            das Leserecht auf der Property nicht mehr gueltig ist
-   */
-  public boolean contains(Object value) {
-    return indexOf(value) >= 0;
-  }
-}
+  /**
+   * Liefert die aktuelle Anzahl an Elementen, die in der Liste gespeichert
+   * sind.
+   * @exception schmitzm.data.property.AccessViolationException falls
+   *            das Leserecht auf der Property nicht mehr gueltig ist
+   */
+  public int getCount() {
+    checkDisposed();
+    int ret = ((ListProperty)object).getCount();
+    incAndCheckMaxAccessTimesReached();
+    return ret;
+  }
+
+  /**
+   * Checkt, ob die Liste leer ist.
+   * @exception schmitzm.data.property.AccessViolationException falls
+   *            das Leserecht auf der Property nicht mehr gueltig ist
+   */
+  public boolean isEmpty() {
+    return getCount() == 0;
+  }
+
+  /**
+   * Liefert den Listen-Index des ersten Vorkommens eines Elements.
+   * @param value Listen-Element
+   * @return -1 falls das Element nicht in der Liste vorhanden ist.
+   * @exception schmitzm.data.property.AccessViolationException falls
+   *            das Leserecht auf der Property nicht mehr gueltig ist
+   */
+  public int indexOf(Object value) {
+    checkDisposed();
+    int ret = ((ListProperty)object).indexOf(value);
+    incAndCheckMaxAccessTimesReached();
+    return ret;
+  }
+
+  /**
+   * Checkt, ob ein Objekt in der Liste vorhanden ist.
+   * @exception schmitzm.data.property.AccessViolationException falls
+   *            das Leserecht auf der Property nicht mehr gueltig ist
+   */
+  public boolean contains(Object value) {
+    return indexOf(value) >= 0;
+  }
+}

Modified: trunk/src/schmitzm/data/property/ListPropertyWriteAccess.java
===================================================================
--- trunk/src/schmitzm/data/property/ListPropertyWriteAccess.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/property/ListPropertyWriteAccess.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,199 +1,217 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data.property;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+/**
+ * Diese Klasse stellt ein Recht auf Schreibzugriff fuer eine
+ * {@link ListProperty} dar. Da Listen dynamisch aufgebaut sind, erweitert sie
+ * hierzu den {@link PropertyWriteAccess} um <code>insert</code>-
+ * und <code>remove</code>-Methoden.<br>
+ * <b>Bemerkung:</b><br>
+ * Um auch den kompletten Lesezugriff zu ermoeglichen, werden zusaetzlich auch
+ * noch einmal alle (neuen) Methoden von {@link ListPropertyReadAccess}
+ * implementiert. Dies ist erforderlich, da diese Klasse von
+ * {@link PropertyWriteAccess} abgeleitet werden muss und doppelte Ableitung
+ * leider nicht moeglich ist.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class ListPropertyWriteAccess extends PropertyWriteAccess {
 
-package schmitzm.data.property;
-
-
-/**
- * Diese Klasse stellt ein Recht auf Schreibzugriff fuer eine
- * {@link ListProperty} dar. Da Listen dynamisch aufgebaut sind, erweitert sie
- * hierzu den {@link PropertyWriteAccess} um <code>insert</code>-
- * und <code>remove</code>-Methoden.<br>
- * <b>Bemerkung:</b><br>
- * Um auch den kompletten Lesezugriff zu ermoeglichen, werden zusaetzlich auch
- * noch einmal alle (neuen) Methoden von {@link ListPropertyReadAccess}
- * implementiert. Dies ist erforderlich, da diese Klasse von
- * {@link PropertyWriteAccess} abgeleitet werden muss und doppelte Ableitung
- * leider nicht moeglich ist.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class ListPropertyWriteAccess extends PropertyWriteAccess {
-
-  /**
-   * Erzeugt ein neues Schreibzugriffsrecht fuer Listen. Die Anzahl an Zugriffen
-   * fuer den Besitzer ist unbegrenzt.
-   * @param object Instanz von <code>ListProperty</code> auf die sich das Recht bezieht
-   * @param owner  Besitzer des Rechts
-   * @see schmitzm.data.property.ListProperty
-   * @exception schmitzm.data.property.AccessViolationException falls das
-   *            angegebene Objekt <b>keine</b> <code>ListProperty</code> ist
-   */
-  public ListPropertyWriteAccess(Accessible object, Object owner) {
-    this(object, owner,UNLIMITED_ACCESSTIMES);
-  }
-
-  /**
-   * Erzeugt ein neues Schreibzugriffsrecht fuer Listen.
-   * @param object Instanz von <code>ListProperty</code> auf die sich das Recht bezieht
-   * @param owner  Besitzer des Rechts
-   * @param maxAccessTimes Anzahl an (Methoden-)Zugriffen, die der Rechtebesitzer
-   *                       taetigen darf, bevor das Recht automatisch entzogen wird
-   * @see schmitzm.data.property.ListProperty
-   * @exception schmitzm.data.property.AccessViolationException falls das
-   *            angegebene Objekt <b>keine</b> <code>ListProperty</code> ist
-   */
-  public ListPropertyWriteAccess(Accessible object, Object owner, int maxAccessTimes) {
-    super(object, owner, maxAccessTimes);
-    if (! (object instanceof ListProperty))
-      throw new AccessViolationException(this,
-          this.getClass().getName() + " can only be instantiated for ListProperties");
-  }
-
-  /**
-   * Fuegt der Liste ein Element (am Ende) hinzu. Kann (seit JDK1.5.0) auch
-   * genutzt werden, wenn es sich bei der Property um einen Build-in-Type handelt.<br>
-   * Iniziiert ein <code>ObjectChangeEvent</code> fuer die Liste.
-   * @param value  neuer Wert fuer die Liste
-   * @exception java.lang.UnsupportedOperationException falls nicht genau ein
-   *            <code>coords</code>-Parameter angegeben wird
-   * @exception java.lang.ClassCastException falls das angegebene Objekt nicht
-   *            zum Property-Typ passt
-   * @exception schmitzm.data.property.AccessViolationException falls
-   *            das Schreibrecht auf der Property nicht mehr gueltig ist
-   */
-  public void addValue(Object value) {
-// Kann so nicht gemacht werden, da bei OneTimeWriteAccess das Recht
-// bei Aufruf der this.getCount()-Methode bereits "verbraucht" wird!!
-// Das anschliessende this.insertValue(..) fuehrt dann zu einer
-// AccessViolationException, da kein Recht mehr besteht!! :-)
-// Loesung: >> direkt auf getCount-Methode des Objekts zugreifen!
-//  insertValue(value, getCount());
-    insertValue(value,((ListProperty)object).getCount());
-  }
-
-  /**
-   * Belegt ein Element der Liste. Kann (seit JDK1.5.0) auch genutzt werden,
-   * wenn es sich bei der Property um einen Build-in-Type handelt.<br>
-   * Iniziiert ein <code>ObjectChangeEvent</code> fuer die Liste.
-   * @param value  neuer Wert fuer das Listen-Element
-   * @param index  Listen-Index fuer das neue Element (alle bestehenden Elemente
-   *               ab (einschliesslich) dieser Position werden nach hinten
-   *               verschoben)
-   * @exception java.lang.ClassCastException falls das angegebene Objekt nicht
-   *            zum Property-Typ passt
-   * @exception schmitzm.data.property.AccessViolationException falls
-   *            das Schreibrecht auf der Property nicht mehr gueltig ist
-   */
-  public void insertValue(Object value, int index) {
-    checkDisposed();
-    ((ListProperty)this.object).insertValue(value,index);
-    incAndCheckMaxAccessTimesReached();
-  }
-
-  /**
-   * Entfernt ein Element aus der Liste.<br>
-   * Iniziiert ein <code>ObjectChangeEvent</code> fuer die Liste.
-   * @param index Listen-Index des zu loeschenden Elements
-   * @exception schmitzm.data.property.AccessViolationException falls
-   *            das Schreibrecht auf der Property nicht mehr gueltig ist
-   */
-  public void removeValue(int index) {
-    checkDisposed();
-    ((ListProperty)this.object).removeValue(index);
-    incAndCheckMaxAccessTimesReached();
-  }
-
-  /**
-   * Entfernt alle Instanzen des angegebenen Objekts aus der Liste (sofern
-   * es vorhanden ist).<br>
-   * Iniziiert ein <code>ObjectChangeEvent</code> fuer die Liste.
-   * @param value das zu entfernende Objekt
-   * @return <code>false</code> falls dass Objekt nicht in der Liste vorhanden war
-   * @exception schmitzm.data.property.AccessViolationException falls
-   *            das Schreibrecht auf der Property nicht mehr gueltig ist
-   */
-  public boolean removeValue(Object value) {
-    checkDisposed();
-    boolean ret = ((ListProperty)this.object).removeValue(value);
-    incAndCheckMaxAccessTimesReached();
-    return ret;
-  }
-
-  /**
-   * Entfernt alle Objekte aus der Liste.<br>
-   * Iniziiert ein <code>ObjectChangeEvent</code> fuer jedes geloeschte
-   * Element der Liste.
-   * @exception schmitzm.data.property.AccessViolationException falls
-   *            das Schreibrecht auf der Property nicht mehr gueltig ist
-   */
-  public void removeAll() {
-    checkDisposed();
-    while ( ((ListProperty)this.object).getCount() > 0 )
-      ((ListProperty)this.object).removeValue(0);
-    incAndCheckMaxAccessTimesReached();
-  }
-
-  ////////////////////////////////////////////////////////////////////////
-  // Folgende Methoden sind identisch zur ListPropertyReadAcces.
-  // Muessen leider doppelt implememtiert werden, da ListPropertyWriteAccess
-  // bereits von PropertyWriteAccess abgeleitet werden muss und doppelte
-  // Ableitung leider nicht moeglich ist.
-  ////////////////////////////////////////////////////////////////////////
-  /**
-   * Liefert die aktuelle Anzahl an Elementen, die in der Liste gespeichert
-   * sind.<br>
-   * Identisch zu {@link ListPropertyReadAccess#getCount()}.
-   * @exception schmitzm.data.property.AccessViolationException falls
-   *            das Schreibrecht auf der Property nicht mehr gueltig ist
-   */
-  public int getCount() {
-    checkDisposed();
-    int ret = ((ListProperty)object).getCount();
-    incAndCheckMaxAccessTimesReached();
-    return ret;
-  }
-
-  /**
-   * Checkt, ob die Liste leer ist.<br>
-   * Identisch zu {@link ListPropertyReadAccess#isEmpty()}.
-   * @exception schmitzm.data.property.AccessViolationException falls
-   *            das Schreibrecht auf der Property nicht mehr gueltig ist
-   */
-  public boolean isEmpty() {
-    return getCount() == 0;
-  }
-
-  /**
-   * Liefert den Listen-Index des ersten Vorkommens eines Elements.<br>
-   * Identisch zu {@link ListPropertyReadAccess#indexOf(Object)}.
-   * @param value Listen-Element
-   * @return -1 falls das Element nicht in der Liste vorhanden ist.
-   * @exception schmitzm.data.property.AccessViolationException falls
-   *            das Schreibrecht auf der Property nicht mehr gueltig ist
-   */
-  public int indexOf(Object value) {
-    checkDisposed();
-    int ret = ((ListProperty)object).indexOf(value);
-    incAndCheckMaxAccessTimesReached();
-    return ret;
-  }
-
-  /**
-   * Checkt, ob ein Objekt in der Liste vorhanden ist.<br>
-   * Identisch zu {@link ListPropertyReadAccess#contains(Object)}.
-   * @exception schmitzm.data.property.AccessViolationException falls
-   *            das Schreibrecht auf der Property nicht mehr gueltig ist
-   */
-  public boolean contains(Object value) {
-    return indexOf(value) >= 0;
-  }
-}
+  /**
+   * Erzeugt ein neues Schreibzugriffsrecht fuer Listen. Die Anzahl an Zugriffen
+   * fuer den Besitzer ist unbegrenzt.
+   * @param object Instanz von <code>ListProperty</code> auf die sich das Recht bezieht
+   * @param owner  Besitzer des Rechts
+   * @see schmitzm.data.property.ListProperty
+   * @exception schmitzm.data.property.AccessViolationException falls das
+   *            angegebene Objekt <b>keine</b> <code>ListProperty</code> ist
+   */
+  public ListPropertyWriteAccess(Accessible object, Object owner) {
+    this(object, owner,UNLIMITED_ACCESSTIMES);
+  }
+
+  /**
+   * Erzeugt ein neues Schreibzugriffsrecht fuer Listen.
+   * @param object Instanz von <code>ListProperty</code> auf die sich das Recht bezieht
+   * @param owner  Besitzer des Rechts
+   * @param maxAccessTimes Anzahl an (Methoden-)Zugriffen, die der Rechtebesitzer
+   *                       taetigen darf, bevor das Recht automatisch entzogen wird
+   * @see schmitzm.data.property.ListProperty
+   * @exception schmitzm.data.property.AccessViolationException falls das
+   *            angegebene Objekt <b>keine</b> <code>ListProperty</code> ist
+   */
+  public ListPropertyWriteAccess(Accessible object, Object owner, int maxAccessTimes) {
+    super(object, owner, maxAccessTimes);
+    if (! (object instanceof ListProperty))
+      throw new AccessViolationException(this,
+          this.getClass().getName() + " can only be instantiated for ListProperties");
+  }
+
+  /**
+   * Fuegt der Liste ein Element (am Ende) hinzu. Kann (seit JDK1.5.0) auch
+   * genutzt werden, wenn es sich bei der Property um einen Build-in-Type handelt.<br>
+   * Iniziiert ein <code>ObjectChangeEvent</code> fuer die Liste.
+   * @param value  neuer Wert fuer die Liste
+   * @exception java.lang.UnsupportedOperationException falls nicht genau ein
+   *            <code>coords</code>-Parameter angegeben wird
+   * @exception java.lang.ClassCastException falls das angegebene Objekt nicht
+   *            zum Property-Typ passt
+   * @exception schmitzm.data.property.AccessViolationException falls
+   *            das Schreibrecht auf der Property nicht mehr gueltig ist
+   */
+  public void addValue(Object value) {
+// Kann so nicht gemacht werden, da bei OneTimeWriteAccess das Recht
+// bei Aufruf der this.getCount()-Methode bereits "verbraucht" wird!!
+// Das anschliessende this.insertValue(..) fuehrt dann zu einer
+// AccessViolationException, da kein Recht mehr besteht!! :-)
+// Loesung: >> direkt auf getCount-Methode des Objekts zugreifen!
+//  insertValue(value, getCount());
+    insertValue(value,((ListProperty)object).getCount());
+  }
+
+  /**
+   * Belegt ein Element der Liste. Kann (seit JDK1.5.0) auch genutzt werden,
+   * wenn es sich bei der Property um einen Build-in-Type handelt.<br>
+   * Iniziiert ein <code>ObjectChangeEvent</code> fuer die Liste.
+   * @param value  neuer Wert fuer das Listen-Element
+   * @param index  Listen-Index fuer das neue Element (alle bestehenden Elemente
+   *               ab (einschliesslich) dieser Position werden nach hinten
+   *               verschoben)
+   * @exception java.lang.ClassCastException falls das angegebene Objekt nicht
+   *            zum Property-Typ passt
+   * @exception schmitzm.data.property.AccessViolationException falls
+   *            das Schreibrecht auf der Property nicht mehr gueltig ist
+   */
+  public void insertValue(Object value, int index) {
+    checkDisposed();
+    ((ListProperty)this.object).insertValue(value,index);
+    incAndCheckMaxAccessTimesReached();
+  }
+
+  /**
+   * Entfernt ein Element aus der Liste.<br>
+   * Iniziiert ein <code>ObjectChangeEvent</code> fuer die Liste.
+   * @param index Listen-Index des zu loeschenden Elements
+   * @exception schmitzm.data.property.AccessViolationException falls
+   *            das Schreibrecht auf der Property nicht mehr gueltig ist
+   */
+  public void removeValue(int index) {
+    checkDisposed();
+    ((ListProperty)this.object).removeValue(index);
+    incAndCheckMaxAccessTimesReached();
+  }
+
+  /**
+   * Entfernt alle Instanzen des angegebenen Objekts aus der Liste (sofern
+   * es vorhanden ist).<br>
+   * Iniziiert ein <code>ObjectChangeEvent</code> fuer die Liste.
+   * @param value das zu entfernende Objekt
+   * @return <code>false</code> falls dass Objekt nicht in der Liste vorhanden war
+   * @exception schmitzm.data.property.AccessViolationException falls
+   *            das Schreibrecht auf der Property nicht mehr gueltig ist
+   */
+  public boolean removeValue(Object value) {
+    checkDisposed();
+    boolean ret = ((ListProperty)this.object).removeValue(value);
+    incAndCheckMaxAccessTimesReached();
+    return ret;
+  }
+
+  /**
+   * Entfernt alle Objekte aus der Liste.<br>
+   * Iniziiert ein <code>ObjectChangeEvent</code> fuer jedes geloeschte
+   * Element der Liste.
+   * @exception schmitzm.data.property.AccessViolationException falls
+   *            das Schreibrecht auf der Property nicht mehr gueltig ist
+   */
+  public void removeAll() {
+    checkDisposed();
+    while ( ((ListProperty)this.object).getCount() > 0 )
+      ((ListProperty)this.object).removeValue(0);
+    incAndCheckMaxAccessTimesReached();
+  }
+
+  ////////////////////////////////////////////////////////////////////////
+  // Folgende Methoden sind identisch zur ListPropertyReadAcces.
+  // Muessen leider doppelt implememtiert werden, da ListPropertyWriteAccess
+  // bereits von PropertyWriteAccess abgeleitet werden muss und doppelte
+  // Ableitung leider nicht moeglich ist.
+  ////////////////////////////////////////////////////////////////////////
+  /**
+   * Liefert die aktuelle Anzahl an Elementen, die in der Liste gespeichert
+   * sind.<br>
+   * Identisch zu {@link ListPropertyReadAccess#getCount()}.
+   * @exception schmitzm.data.property.AccessViolationException falls
+   *            das Schreibrecht auf der Property nicht mehr gueltig ist
+   */
+  public int getCount() {
+    checkDisposed();
+    int ret = ((ListProperty)object).getCount();
+    incAndCheckMaxAccessTimesReached();
+    return ret;
+  }
+
+  /**
+   * Checkt, ob die Liste leer ist.<br>
+   * Identisch zu {@link ListPropertyReadAccess#isEmpty()}.
+   * @exception schmitzm.data.property.AccessViolationException falls
+   *            das Schreibrecht auf der Property nicht mehr gueltig ist
+   */
+  public boolean isEmpty() {
+    return getCount() == 0;
+  }
+
+  /**
+   * Liefert den Listen-Index des ersten Vorkommens eines Elements.<br>
+   * Identisch zu {@link ListPropertyReadAccess#indexOf(Object)}.
+   * @param value Listen-Element
+   * @return -1 falls das Element nicht in der Liste vorhanden ist.
+   * @exception schmitzm.data.property.AccessViolationException falls
+   *            das Schreibrecht auf der Property nicht mehr gueltig ist
+   */
+  public int indexOf(Object value) {
+    checkDisposed();
+    int ret = ((ListProperty)object).indexOf(value);
+    incAndCheckMaxAccessTimesReached();
+    return ret;
+  }
+
+  /**
+   * Checkt, ob ein Objekt in der Liste vorhanden ist.<br>
+   * Identisch zu {@link ListPropertyReadAccess#contains(Object)}.
+   * @exception schmitzm.data.property.AccessViolationException falls
+   *            das Schreibrecht auf der Property nicht mehr gueltig ist
+   */
+  public boolean contains(Object value) {
+    return indexOf(value) >= 0;
+  }
+}

Modified: trunk/src/schmitzm/data/property/MatrixProperty.java
===================================================================
--- trunk/src/schmitzm/data/property/MatrixProperty.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/property/MatrixProperty.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,327 +1,345 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data.property;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.data.property;
-
 import schmitzm.data.ObjectStructure;
 import schmitzm.data.event.Invoker;
 import schmitzm.data.event.ObjectChangeEvent;
 import schmitzm.lang.MultiDimArray;
-
-/**
- * Diese Klasse stellt eine Matrix-Eigenschaft dar, die Objekte eines bestimmten
- * Typs aufnehmen kann. Die Dimension und Groesse der Matrix wird bei der
- * Instanziierung festgelegt und kann nicht geaendert werden.<br>
- * Der Zugriff auf die Property kann durch Zugriffsrechte kontrolliert werden.
- * Ein Zugriff (lesend oder schreibend) ist nur ueber ein entsprechendes
- * Zugriffsrecht ({@link Access}) moeglich. Standardmaessig ist unbegrenzter
- * Zugriff eingestellt. Durch Angabe von {@link ValuePropertyAccessParameters}
- * kann jedoch benutzerdefiniert festgelegt werden, wie viele Objekte gleichzeitig
- * Lese- und/oder Schreibzugriff erlangen duerfen.
- * @see schmitzm.data.property.ValueProperty#getReadAccess(Object)
- * @see schmitzm.data.property.ValueProperty#getWriteAccess(Object)
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class MatrixProperty extends ValueProperty {
-  // Groesse der Matrix merken (aus Effizienzgruenden!)
-  private int[] size = null;
-
-  /**
-   * Speichert die Matrix als <code>java.lang.reflect.Array</code>.
-   * @see java.lang.reflect.Array
-   */
-  protected Object matrix = null;
-
-  /**
-   * Speichert die Groessenangabe der Matrix als <code>String</code> der Form
-   * <code>"(d1,d2,d3,...)</code>.
-   */
-  protected String sizeDesc = "";
-
-  /**
-   * Erzeugt eine Matrix-Eigenschaft. Die Dimension der Matrix ist implizit
-   * durch die Größe des <code>size</code>-Arrays gegeben
-   * @param name Name der Eigenschaft
-   * @param size Groesse der Matrix in jeder Dimension
-   * @param elementType Matrix kann nur Elemente dieses Daten-Typs aufnehmen
-   * @param params Parameter fuer die Verwaltung des Zugriffsrechts
-   * @see schmitzm.data.property.ValuePropertyAccessParameters
-   */
-  public MatrixProperty(String name, int[] size, ValuePropertyType elementType, ValuePropertyAccessParameters params) {
-    super(name, elementType, params);
-    this.size      = size.clone();
-    this.matrix    = MultiDimArray.newInstance(elementType.getType(),size);
-    // Groessenbeschreibung zusammensetzen
-    sizeDesc = "(";
-    for (int d=0; d<size.length; d++) {
-      if ( d > 0 ) sizeDesc+=",";
-      sizeDesc+=size[d];
-    }
-    sizeDesc+=")";
-  }
-
-  /**
-   * Erzeugt eine Matrix-Eigenschaft. Die Dimension der Matrix ist implizit
-   * durch die Größe des <code>size</code>-Arrays gegeben.
-   * Der Zugriff auf die Eigenschaft ist uneingeschraengt (beliebig viele
-   * Lese- und beliebig viele Schreibrechte).
-   * @param name Name der Eigenschaft
-   * @param size Groesse der Matrix in jeder Dimension
-   * @param elementType Matrix kann nur Elemente dieses Daten-Typs aufnehmen
-   * @see schmitzm.data.property.ValuePropertyAccessParameters#UNLIMITED_ACCESS
-   */
-  public MatrixProperty(String name, int[] size, ValuePropertyType elementType) {
-    this(name, size, elementType, ValuePropertyAccessParameters.UNLIMITED_ACCESS);
-  }
-
-  /**
-   * Erzeugt eine Matrix-Eigenschaft. Als Typ kann auch ein Build-in-Type
-   * angegeben werden (z.B. int.class). Die Dimension der Matrix ist implizit
-   * durch die Größe des <code>size</code>-Arrays gegeben
-   * @param name Name der Eigenschaft
-   * @param size Groesse der Matrix in jeder Dimension
-   * @param elementType Matrix kann nur Elemente dieses Daten-Typs aufnehmen
-   * @param params Parameter fuer die Verwaltung des Zugriffsrechts
-   * @see schmitzm.data.property.ValuePropertyAccessParameters
-   */
-  public MatrixProperty(String name, int[] size, Class elementType, ValuePropertyAccessParameters params) {
-    this(name,size,new ValuePropertyType(elementType),params);
-  }
-
-  /**
-   * Erzeugt eine Matrix-Eigenschaft. Als Typ kann auch ein Build-in-Type
-   * angegeben werden (z.B. int.class). Die Dimension der Matrix ist implizit
-   * durch die Größe des <code>size</code>-Arrays gegeben.
-   * Der Zugriff auf die Eigenschaft ist uneingeschraengt (beliebig viele
-   * Lese- und beliebig viele Schreibrechte).
-   * @param name Name der Eigenschaft
-   * @param size Groesse der Matrix in jeder Dimension
-   * @param elementType Matrix kann nur Elemente dieses Daten-Typs aufnehmen
-   * @see schmitzm.data.property.ValuePropertyAccessParameters#UNLIMITED_ACCESS
-   */
-  public MatrixProperty(String name, int[] size, Class elementType) {
-    this(name, size, elementType, ValuePropertyAccessParameters.UNLIMITED_ACCESS);
-  }
-
-  /**
-   * Erzeugt eine Matrix-Eigenschaft. Als Typ kann auch ein Build-in-Type
-   * angegeben werden (z.B. int.class). Die Dimension der Matrix ist implizit
-   * durch die Größe des <code>size</code>-Arrays gegeben
-   * @param name Name der Eigenschaft
-   * @param size Groesse der Matrix in jeder Dimension
-   * @param sample Matrix kann nur Elemente dieser Struktur aufnehmen
-   * @param params Parameter fuer die Verwaltung des Zugriffsrechts
-   * @see schmitzm.data.property.ValuePropertyAccessParameters
-   */
-  public MatrixProperty(String name, int[] size, ObjectStructure sample, ValuePropertyAccessParameters params) {
-    this(name,size,new ValuePropertyType(sample),params);
-  }
-
-  /**
-   * Erzeugt eine Matrix-Eigenschaft. Als Typ kann auch ein Build-in-Type
-   * angegeben werden (z.B. int.class). Die Dimension der Matrix ist implizit
-   * durch die Größe des <code>size</code>-Arrays gegeben.
-   * Der Zugriff auf die Eigenschaft ist uneingeschraengt (beliebig viele
-   * Lese- und beliebig viele Schreibrechte).
-   * @param name Name der Eigenschaft
-   * @param size Groesse der Matrix in jeder Dimension
-   * @param sample Matrix kann nur Elemente dieser Struktur aufnehmen
-   * @see schmitzm.data.property.ValuePropertyAccessParameters#UNLIMITED_ACCESS
-   */
-  public MatrixProperty(String name, int[] size, ObjectStructure sample) {
-    this(name, size, sample, ValuePropertyAccessParameters.UNLIMITED_ACCESS);
-  }
-
-  /**
-   * Erzeugt eine Matrix-Eigenschaft. Als Typ kann auch ein Build-in-Type
-   * angegeben werden (z.B. int.class). Die Dimension der Matrix ist implizit
-   * durch die Größe des <code>size</code>-Arrays gegeben
-   * @param name Name der Eigenschaft
-   * @param size Groesse der Matrix in jeder Dimension
-   * @param sampleData Bestimmt die Element-Struktur, die in der <code>MatrixProperty</code>
-   *                   gespeichert werden kann (das Objekt wird <b>nicht</b>
-   *                   in die Matrix aufgenommen!!)
-   * @param params Parameter fuer die Verwaltung des Zugriffsrechts
-   * @see schmitzm.data.property.ValuePropertyAccessParameters
-   */
-  public MatrixProperty(String name, int[] size, Object sampleData, ValuePropertyAccessParameters params) {
-    this(name,size,ValuePropertyType.createValuePropertyType(sampleData),params);
-  }
-
-  /**
-   * Erzeugt eine Matrix-Eigenschaft. Als Typ kann auch ein Build-in-Type
-   * angegeben werden (z.B. int.class). Die Dimension der Matrix ist implizit
-   * durch die Größe des <code>size</code>-Arrays gegeben.
-   * Der Zugriff auf die Eigenschaft ist uneingeschraengt (beliebig viele
-   * Lese- und beliebig viele Schreibrechte).
-   * @param name Name der Eigenschaft
-   * @param size Groesse der Matrix in jeder Dimension
-   * @param sampleData Bestimmt die Element-Struktur, die in der <code>MatrixProperty</code>
-   *                   gespeichert werden kann (das Objekt wird <b>nicht</b>
-   *                   in die Matrix aufgenommen!!)
-   * @see schmitzm.data.property.ValuePropertyAccessParameters#UNLIMITED_ACCESS
-   */
-  public MatrixProperty(String name, int[] size, Object sampleData) {
-    this(name, size, sampleData, ValuePropertyAccessParameters.UNLIMITED_ACCESS);
-  }
-
-  /**
-   * Erzeugt eine Matrix-Eigenschaft. Als Elemente kann diese saemtliche Objekte
-   * aufnehmen, die von <code>java.lang.Object</code> abgeleitet sind
-   * (also <u>keine</u> Build-in-Types!!). Die Dimension der Matrix ist implizit
-   * durch die Größe des <code>size</code>-Arrays gegeben
-   * @param name Name der Eigenschaft
-   * @param size Groesse der Matrix in jeder Dimension
-   * @param params Parameter fuer die Verwaltung des Zugriffsrechts
-   * @see schmitzm.data.property.ValuePropertyAccessParameters
-   */
-
-  public MatrixProperty(String name, int[] size, ValuePropertyAccessParameters params) {
-    this(name, size, Object.class,params);
-  }
-
-  /**
-   * Erzeugt eine Matrix-Eigenschaft. Als Elemente kann diese saemtliche Objekte
-   * aufnehmen, die von <code>java.lang.Object</code> abgeleitet sind
-   * (also <u>keine</u> Build-in-Types!!). Die Dimension der Matrix ist implizit
-   * durch die Größe des <code>size</code>-Arrays gegeben.
-   * Der Zugriff auf die Eigenschaft ist uneingeschraengt (beliebig viele
-   * Lese- und beliebig viele Schreibrechte).
-   * @param name Name der Eigenschaft
-   * @param size Groesse der Matrix in jeder Dimension
-   * @see schmitzm.data.property.ValuePropertyAccessParameters#UNLIMITED_ACCESS
-   */
-
-  public MatrixProperty(String name, int[] size) {
-    this(name, size, Object.class, ValuePropertyAccessParameters.UNLIMITED_ACCESS);
-  }
-
-  /**
-   * Zerstoert die Matrix, indem die auf <code>null</code> gesetzt wird.
-   */
-  public void dispose() {
-    matrix = null;
-    super.dispose();
-  }
-
-  /**
-   * Liefert eine neue, leerer <code>MatrixProperty</code> mit identischem
-   * Namen, Typ, geleicher Groesse und gleichen Zugriffsparemetern.
-   */
-  public MatrixProperty cloneStructure() {
-    return new MatrixProperty( getName(), getSize(), getPropertyType(), getAccessParameters() );
-  }
-
-  ///////////////////////////////////////////////////////////////////
-  // Implementierung von ValueProperty
-  ///////////////////////////////////////////////////////////////////
-
-  /**
-   * Liefert ein Element der Matrix. Kann (seit JDK1.5.0) auch genutzt werden,
-   * wenn es sich bei der Property um einen Build-in-Type handelt.
-   * @param coords Position (Koordinaten) der Matrix
-   * @exception java.lang.UnsupportedOperationException falls die Anzahl der
-   *            Koordinaten nicht genau der Matrix-Dimension entspricht
-   */
-  protected Object getValue(int... coords) {
-    if (coords.length != getDimension())
-      throw new UnsupportedOperationException("The MatrixProperty is ".concat(""+getDimension()).concat("-dimensional. Thus exactly ").concat(""+getDimension()).concat(" parameters are needed for getValue(..).") );
-    return MultiDimArray.get(matrix,coords);
-  }
-
-  /**
-   * Setzt ein Element der Matrix. Kann (seit JDK1.5.0) auch genutzt werden,
-   * wenn es sich bei der Property um einen Build-in-Type handelt.<br>
-   * Iniziiert ein <code>ObjectChangeEvent</code> fuer die Liste.
-   * @param value  Wert fuer das Matrix-Element
-   * @param coords Position (Koordinaten) der Matrix
-   * @exception java.lang.UnsupportedOperationException falls die Anzahl der
-   *            Koordinaten nicht genau der Matrix-Dimension entspricht
-   * @exception java.lang.ClassCastException falls das angegebene Objekt nicht
-   *            zum Property-Typ passt
-   */
-  protected void setValue(Object value, int... coords) {
-    if (coords.length != getDimension())
-      throw new UnsupportedOperationException("The MatrixProperty is ".concat(""+getDimension()).concat("-dimensional. Thus exactly ").concat(""+getDimension()).concat(" parameters are needed for setValue(..).") );
-    if ( value!=null && !this.isValid( value.getClass() ) )
-      throw new ClassCastException(value.getClass().getName().concat(" can not be stored in a MatrixProperty[").concat(this.getType().getName()).concat("]"));
-
-    // altes Objekt merken fuer Event
-    Object oldValue = getValue(coords);
-    MultiDimArray.set(matrix,coords,value);
-
-    this.fireEvent( new ObjectChangeEvent(
-      new Invoker(this),
-      oldValue,
-      value
-    ) );
-  }
-
-  ///////////////////////////////////////////////////////////////////
-  // Neue Matrix-Funktionen
-  ///////////////////////////////////////////////////////////////////
-  /**
-   * Liefert die Dimension der Matrix.
-   */
-  public int getDimension() {
-    return this.size.length;
-  }
-
-  /**
-   * Liefert die Groesse der Matrix in einer Dimension.
-   * @param dim Index der Dimension (beginnend bei 0)
-   */
-  public int getSize(int dim) {
-    return size[dim];
-  }
-
-  /**
-   * Liefert die Groesse der Matrix in allen Dimensionen.
-   */
-  public int[] getSize() {
-    return size.clone();
-  }
-
-  /**
-   * Liefert die Groesse der Matrix in allen Dimensionen als Beschreibung.
-   */
-  public String getSizeText() {
-    return sizeDesc;
-  }
-
-  ///////////////////////////////////////////////////////////////////
-  // Implementierung von ObjectStructure
-  ///////////////////////////////////////////////////////////////////
-  /**
-   * Liefert <code>true</code>, da eine Matrix-Eigenschaft immer
-   * aus mehreren Werten besteht.
-   */
-  public boolean containsMultipleValues() {
-    return true;
-  }
-
-//  /**
-//   * Liefert <code>true</code>, da neben dem Klassennamen auch die groesse
-//   * der Matrix ausgewiesen werden soll.
-//   */
-//  public boolean isStructureNamed() {
-//    return true;
-//  }
-//
-//  /**
-//   * Liefert <code>true</code>, da neben dem Klassennamen auch die groesse
-//   * der Matrix ausgewiesen werden soll.
-//   */
-//  public String getStructureName() {
-//    return this.getClass().getSimpleName().concat( getSizeText() );
-//  }
-}
+
+/**
+ * Diese Klasse stellt eine Matrix-Eigenschaft dar, die Objekte eines bestimmten
+ * Typs aufnehmen kann. Die Dimension und Groesse der Matrix wird bei der
+ * Instanziierung festgelegt und kann nicht geaendert werden.<br>
+ * Der Zugriff auf die Property kann durch Zugriffsrechte kontrolliert werden.
+ * Ein Zugriff (lesend oder schreibend) ist nur ueber ein entsprechendes
+ * Zugriffsrecht ({@link Access}) moeglich. Standardmaessig ist unbegrenzter
+ * Zugriff eingestellt. Durch Angabe von {@link ValuePropertyAccessParameters}
+ * kann jedoch benutzerdefiniert festgelegt werden, wie viele Objekte gleichzeitig
+ * Lese- und/oder Schreibzugriff erlangen duerfen.
+ * @see schmitzm.data.property.ValueProperty#getReadAccess(Object)
+ * @see schmitzm.data.property.ValueProperty#getWriteAccess(Object)
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class MatrixProperty extends ValueProperty {
+  // Groesse der Matrix merken (aus Effizienzgruenden!)
+  private int[] size = null;
+
+  /**
+   * Speichert die Matrix als <code>java.lang.reflect.Array</code>.
+   * @see java.lang.reflect.Array
+   */
+  protected Object matrix = null;
+
+  /**
+   * Speichert die Groessenangabe der Matrix als <code>String</code> der Form
+   * <code>"(d1,d2,d3,...)</code>.
+   */
+  protected String sizeDesc = "";
+
+  /**
+   * Erzeugt eine Matrix-Eigenschaft. Die Dimension der Matrix ist implizit
+   * durch die Größe des <code>size</code>-Arrays gegeben
+   * @param name Name der Eigenschaft
+   * @param size Groesse der Matrix in jeder Dimension
+   * @param elementType Matrix kann nur Elemente dieses Daten-Typs aufnehmen
+   * @param params Parameter fuer die Verwaltung des Zugriffsrechts
+   * @see schmitzm.data.property.ValuePropertyAccessParameters
+   */
+  public MatrixProperty(String name, int[] size, ValuePropertyType elementType, ValuePropertyAccessParameters params) {
+    super(name, elementType, params);
+    this.size      = size.clone();
+    this.matrix    = MultiDimArray.newInstance(elementType.getType(),size);
+    // Groessenbeschreibung zusammensetzen
+    sizeDesc = "(";
+    for (int d=0; d<size.length; d++) {
+      if ( d > 0 ) sizeDesc+=",";
+      sizeDesc+=size[d];
+    }
+    sizeDesc+=")";
+  }
+
+  /**
+   * Erzeugt eine Matrix-Eigenschaft. Die Dimension der Matrix ist implizit
+   * durch die Größe des <code>size</code>-Arrays gegeben.
+   * Der Zugriff auf die Eigenschaft ist uneingeschraengt (beliebig viele
+   * Lese- und beliebig viele Schreibrechte).
+   * @param name Name der Eigenschaft
+   * @param size Groesse der Matrix in jeder Dimension
+   * @param elementType Matrix kann nur Elemente dieses Daten-Typs aufnehmen
+   * @see schmitzm.data.property.ValuePropertyAccessParameters#UNLIMITED_ACCESS
+   */
+  public MatrixProperty(String name, int[] size, ValuePropertyType elementType) {
+    this(name, size, elementType, ValuePropertyAccessParameters.UNLIMITED_ACCESS);
+  }
+
+  /**
+   * Erzeugt eine Matrix-Eigenschaft. Als Typ kann auch ein Build-in-Type
+   * angegeben werden (z.B. int.class). Die Dimension der Matrix ist implizit
+   * durch die Größe des <code>size</code>-Arrays gegeben
+   * @param name Name der Eigenschaft
+   * @param size Groesse der Matrix in jeder Dimension
+   * @param elementType Matrix kann nur Elemente dieses Daten-Typs aufnehmen
+   * @param params Parameter fuer die Verwaltung des Zugriffsrechts
+   * @see schmitzm.data.property.ValuePropertyAccessParameters
+   */
+  public MatrixProperty(String name, int[] size, Class elementType, ValuePropertyAccessParameters params) {
+    this(name,size,new ValuePropertyType(elementType),params);
+  }
+
+  /**
+   * Erzeugt eine Matrix-Eigenschaft. Als Typ kann auch ein Build-in-Type
+   * angegeben werden (z.B. int.class). Die Dimension der Matrix ist implizit
+   * durch die Größe des <code>size</code>-Arrays gegeben.
+   * Der Zugriff auf die Eigenschaft ist uneingeschraengt (beliebig viele
+   * Lese- und beliebig viele Schreibrechte).
+   * @param name Name der Eigenschaft
+   * @param size Groesse der Matrix in jeder Dimension
+   * @param elementType Matrix kann nur Elemente dieses Daten-Typs aufnehmen
+   * @see schmitzm.data.property.ValuePropertyAccessParameters#UNLIMITED_ACCESS
+   */
+  public MatrixProperty(String name, int[] size, Class elementType) {
+    this(name, size, elementType, ValuePropertyAccessParameters.UNLIMITED_ACCESS);
+  }
+
+  /**
+   * Erzeugt eine Matrix-Eigenschaft. Als Typ kann auch ein Build-in-Type
+   * angegeben werden (z.B. int.class). Die Dimension der Matrix ist implizit
+   * durch die Größe des <code>size</code>-Arrays gegeben
+   * @param name Name der Eigenschaft
+   * @param size Groesse der Matrix in jeder Dimension
+   * @param sample Matrix kann nur Elemente dieser Struktur aufnehmen
+   * @param params Parameter fuer die Verwaltung des Zugriffsrechts
+   * @see schmitzm.data.property.ValuePropertyAccessParameters
+   */
+  public MatrixProperty(String name, int[] size, ObjectStructure sample, ValuePropertyAccessParameters params) {
+    this(name,size,new ValuePropertyType(sample),params);
+  }
+
+  /**
+   * Erzeugt eine Matrix-Eigenschaft. Als Typ kann auch ein Build-in-Type
+   * angegeben werden (z.B. int.class). Die Dimension der Matrix ist implizit
+   * durch die Größe des <code>size</code>-Arrays gegeben.
+   * Der Zugriff auf die Eigenschaft ist uneingeschraengt (beliebig viele
+   * Lese- und beliebig viele Schreibrechte).
+   * @param name Name der Eigenschaft
+   * @param size Groesse der Matrix in jeder Dimension
+   * @param sample Matrix kann nur Elemente dieser Struktur aufnehmen
+   * @see schmitzm.data.property.ValuePropertyAccessParameters#UNLIMITED_ACCESS
+   */
+  public MatrixProperty(String name, int[] size, ObjectStructure sample) {
+    this(name, size, sample, ValuePropertyAccessParameters.UNLIMITED_ACCESS);
+  }
+
+  /**
+   * Erzeugt eine Matrix-Eigenschaft. Als Typ kann auch ein Build-in-Type
+   * angegeben werden (z.B. int.class). Die Dimension der Matrix ist implizit
+   * durch die Größe des <code>size</code>-Arrays gegeben
+   * @param name Name der Eigenschaft
+   * @param size Groesse der Matrix in jeder Dimension
+   * @param sampleData Bestimmt die Element-Struktur, die in der <code>MatrixProperty</code>
+   *                   gespeichert werden kann (das Objekt wird <b>nicht</b>
+   *                   in die Matrix aufgenommen!!)
+   * @param params Parameter fuer die Verwaltung des Zugriffsrechts
+   * @see schmitzm.data.property.ValuePropertyAccessParameters
+   */
+  public MatrixProperty(String name, int[] size, Object sampleData, ValuePropertyAccessParameters params) {
+    this(name,size,ValuePropertyType.createValuePropertyType(sampleData),params);
+  }
+
+  /**
+   * Erzeugt eine Matrix-Eigenschaft. Als Typ kann auch ein Build-in-Type
+   * angegeben werden (z.B. int.class). Die Dimension der Matrix ist implizit
+   * durch die Größe des <code>size</code>-Arrays gegeben.
+   * Der Zugriff auf die Eigenschaft ist uneingeschraengt (beliebig viele
+   * Lese- und beliebig viele Schreibrechte).
+   * @param name Name der Eigenschaft
+   * @param size Groesse der Matrix in jeder Dimension
+   * @param sampleData Bestimmt die Element-Struktur, die in der <code>MatrixProperty</code>
+   *                   gespeichert werden kann (das Objekt wird <b>nicht</b>
+   *                   in die Matrix aufgenommen!!)
+   * @see schmitzm.data.property.ValuePropertyAccessParameters#UNLIMITED_ACCESS
+   */
+  public MatrixProperty(String name, int[] size, Object sampleData) {
+    this(name, size, sampleData, ValuePropertyAccessParameters.UNLIMITED_ACCESS);
+  }
+
+  /**
+   * Erzeugt eine Matrix-Eigenschaft. Als Elemente kann diese saemtliche Objekte
+   * aufnehmen, die von <code>java.lang.Object</code> abgeleitet sind
+   * (also <u>keine</u> Build-in-Types!!). Die Dimension der Matrix ist implizit
+   * durch die Größe des <code>size</code>-Arrays gegeben
+   * @param name Name der Eigenschaft
+   * @param size Groesse der Matrix in jeder Dimension
+   * @param params Parameter fuer die Verwaltung des Zugriffsrechts
+   * @see schmitzm.data.property.ValuePropertyAccessParameters
+   */
+
+  public MatrixProperty(String name, int[] size, ValuePropertyAccessParameters params) {
+    this(name, size, Object.class,params);
+  }
+
+  /**
+   * Erzeugt eine Matrix-Eigenschaft. Als Elemente kann diese saemtliche Objekte
+   * aufnehmen, die von <code>java.lang.Object</code> abgeleitet sind
+   * (also <u>keine</u> Build-in-Types!!). Die Dimension der Matrix ist implizit
+   * durch die Größe des <code>size</code>-Arrays gegeben.
+   * Der Zugriff auf die Eigenschaft ist uneingeschraengt (beliebig viele
+   * Lese- und beliebig viele Schreibrechte).
+   * @param name Name der Eigenschaft
+   * @param size Groesse der Matrix in jeder Dimension
+   * @see schmitzm.data.property.ValuePropertyAccessParameters#UNLIMITED_ACCESS
+   */
+
+  public MatrixProperty(String name, int[] size) {
+    this(name, size, Object.class, ValuePropertyAccessParameters.UNLIMITED_ACCESS);
+  }
+
+  /**
+   * Zerstoert die Matrix, indem die auf <code>null</code> gesetzt wird.
+   */
+  public void dispose() {
+    matrix = null;
+    super.dispose();
+  }
+
+  /**
+   * Liefert eine neue, leerer <code>MatrixProperty</code> mit identischem
+   * Namen, Typ, geleicher Groesse und gleichen Zugriffsparemetern.
+   */
+  public MatrixProperty cloneStructure() {
+    return new MatrixProperty( getName(), getSize(), getPropertyType(), getAccessParameters() );
+  }
+
+  ///////////////////////////////////////////////////////////////////
+  // Implementierung von ValueProperty
+  ///////////////////////////////////////////////////////////////////
+
+  /**
+   * Liefert ein Element der Matrix. Kann (seit JDK1.5.0) auch genutzt werden,
+   * wenn es sich bei der Property um einen Build-in-Type handelt.
+   * @param coords Position (Koordinaten) der Matrix
+   * @exception java.lang.UnsupportedOperationException falls die Anzahl der
+   *            Koordinaten nicht genau der Matrix-Dimension entspricht
+   */
+  protected Object getValue(int... coords) {
+    if (coords.length != getDimension())
+      throw new UnsupportedOperationException("The MatrixProperty is ".concat(""+getDimension()).concat("-dimensional. Thus exactly ").concat(""+getDimension()).concat(" parameters are needed for getValue(..).") );
+    return MultiDimArray.get(matrix,coords);
+  }
+
+  /**
+   * Setzt ein Element der Matrix. Kann (seit JDK1.5.0) auch genutzt werden,
+   * wenn es sich bei der Property um einen Build-in-Type handelt.<br>
+   * Iniziiert ein <code>ObjectChangeEvent</code> fuer die Liste.
+   * @param value  Wert fuer das Matrix-Element
+   * @param coords Position (Koordinaten) der Matrix
+   * @exception java.lang.UnsupportedOperationException falls die Anzahl der
+   *            Koordinaten nicht genau der Matrix-Dimension entspricht
+   * @exception java.lang.ClassCastException falls das angegebene Objekt nicht
+   *            zum Property-Typ passt
+   */
+  protected void setValue(Object value, int... coords) {
+    if (coords.length != getDimension())
+      throw new UnsupportedOperationException("The MatrixProperty is ".concat(""+getDimension()).concat("-dimensional. Thus exactly ").concat(""+getDimension()).concat(" parameters are needed for setValue(..).") );
+    if ( value!=null && !this.isValid( value.getClass() ) )
+      throw new ClassCastException(value.getClass().getName().concat(" can not be stored in a MatrixProperty[").concat(this.getType().getName()).concat("]"));
+
+    // altes Objekt merken fuer Event
+    Object oldValue = getValue(coords);
+    MultiDimArray.set(matrix,coords,value);
+
+    this.fireEvent( new ObjectChangeEvent(
+      new Invoker(this),
+      oldValue,
+      value
+    ) );
+  }
+
+  ///////////////////////////////////////////////////////////////////
+  // Neue Matrix-Funktionen
+  ///////////////////////////////////////////////////////////////////
+  /**
+   * Liefert die Dimension der Matrix.
+   */
+  public int getDimension() {
+    return this.size.length;
+  }
+
+  /**
+   * Liefert die Groesse der Matrix in einer Dimension.
+   * @param dim Index der Dimension (beginnend bei 0)
+   */
+  public int getSize(int dim) {
+    return size[dim];
+  }
+
+  /**
+   * Liefert die Groesse der Matrix in allen Dimensionen.
+   */
+  public int[] getSize() {
+    return size.clone();
+  }
+
+  /**
+   * Liefert die Groesse der Matrix in allen Dimensionen als Beschreibung.
+   */
+  public String getSizeText() {
+    return sizeDesc;
+  }
+
+  ///////////////////////////////////////////////////////////////////
+  // Implementierung von ObjectStructure
+  ///////////////////////////////////////////////////////////////////
+  /**
+   * Liefert <code>true</code>, da eine Matrix-Eigenschaft immer
+   * aus mehreren Werten besteht.
+   */
+  public boolean containsMultipleValues() {
+    return true;
+  }
+
+//  /**
+//   * Liefert <code>true</code>, da neben dem Klassennamen auch die groesse
+//   * der Matrix ausgewiesen werden soll.
+//   */
+//  public boolean isStructureNamed() {
+//    return true;
+//  }
+//
+//  /**
+//   * Liefert <code>true</code>, da neben dem Klassennamen auch die groesse
+//   * der Matrix ausgewiesen werden soll.
+//   */
+//  public String getStructureName() {
+//    return this.getClass().getSimpleName().concat( getSizeText() );
+//  }
+}

Modified: trunk/src/schmitzm/data/property/Properties.java
===================================================================
--- trunk/src/schmitzm/data/property/Properties.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/property/Properties.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,82 +1,100 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data.property;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+import schmitzm.data.ObjectStructure;
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+/**
+ * Diese Interface sollten alle Objekte implementieren, die sich (fest) aus
+ * einzelnen Eigenschaften ({@link Property Properties}) zusammensetzen.
+ * Die Methoden des Interface liefern den Zugriff auf die einzelnen Eigenschaften.
+ * Das Hinzufuegen oder Entfernen von Eigenschaften ist durch dieses Interface
+ * nicht moeglich.
+ * @see schmitzm.data.property.DynamicProperties
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public interface Properties extends ObjectStructure {
+  /**
+   * Liefert die Anzahl an Eigenschaften des Objekts.
+   */
+  public int getPropertyCount();
 
-package schmitzm.data.property;
-
-import schmitzm.data.ObjectStructure;
-
-/**
- * Diese Interface sollten alle Objekte implementieren, die sich (fest) aus
- * einzelnen Eigenschaften ({@link Property Properties}) zusammensetzen.
- * Die Methoden des Interface liefern den Zugriff auf die einzelnen Eigenschaften.
- * Das Hinzufuegen oder Entfernen von Eigenschaften ist durch dieses Interface
- * nicht moeglich.
- * @see schmitzm.data.property.DynamicProperties
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public interface Properties extends ObjectStructure {
-  /**
-   * Liefert die Anzahl an Eigenschaften des Objekts.
-   */
-  public int getPropertyCount();
-
-  /**
-   * Liefert die Eigenschaften des Objekts als Array. Wenn das Objekt (noch)
-   * keine Eigenschaften besitzt, sollte ein leerer Array (und nicht <code>null</code>!)
-   * zurueckgegeben werden!
-   */
-  public Property[] getProperties();
-
-  /**
-   * Liefert alle Eigenschaften des Objekts, die einem bestimmten
-   * Typ angehoeren. Als Typ kann sowohl ein bestimmter <code>Property</code>-Untertyp
-   * angegeben werden (z.B. {@link ListProperty}) oder ein Objekt-Typ (Typ
-   * den eine Property aufnehmen kann; z.B. <code>int.class</code>).<br>
-   * Da die Methode wiederum eine <code>Properties</code>-Instanz liefert,
-   * lassen sich recht einfach verschiedene Filter hintereinander anwenden:<br>
-   * <br>
-   * <center><code>
-   * Properties.getProperties(ListProperty.class).getProperties(int.class).getPropertyNames()
-   * </code></center>
-   * <br>
-   * liefert z.B. die Namen aller Listen-Eigenschaften eines Objekts, die
-   * <code>int</code>-Werte aufnehmen koennen.<br>
-   * <b>Bemerke:</b><br>
-   * Wenn das Objekt keine Eigenschaften des angegebenen Typs besitzt, sollte
-   * eine leere Property-Menge (z.B. {@link PropertySet}) zurueckgegeben werden
-   * und <b>nicht</b> <code>null</code>!
-   */
-  public Properties getProperties(Class type);
-
-  /**
-   * Liefert die Namen aller Eigenschaften des Objekts.
-   */
-  public String[] getPropertyNames();
-
-  /**
-   * Liefert die Typen aller Eigenschaften des Objekts.
-   */
-  public PropertyType[] getPropertyTypes();
-
-  /**
-   * Liefert eine Eigenschaft des Objekts.
-   * @param name Name der Eigenschaft
-   * @return <code>null</code> falls das Objekt keine Eigenschaft mit dem
-   *         Namen besitzt
-   */
-  public Property getProperty(String name);
-
-  /**
-   * Prueft, ob das Objekt eine bestimmte Eigenschaft besitzt.
-   */
-  public boolean containsProperty(String name);
-}
+  /**
+   * Liefert die Eigenschaften des Objekts als Array. Wenn das Objekt (noch)
+   * keine Eigenschaften besitzt, sollte ein leerer Array (und nicht <code>null</code>!)
+   * zurueckgegeben werden!
+   */
+  public Property[] getProperties();
+
+  /**
+   * Liefert alle Eigenschaften des Objekts, die einem bestimmten
+   * Typ angehoeren. Als Typ kann sowohl ein bestimmter <code>Property</code>-Untertyp
+   * angegeben werden (z.B. {@link ListProperty}) oder ein Objekt-Typ (Typ
+   * den eine Property aufnehmen kann; z.B. <code>int.class</code>).<br>
+   * Da die Methode wiederum eine <code>Properties</code>-Instanz liefert,
+   * lassen sich recht einfach verschiedene Filter hintereinander anwenden:<br>
+   * <br>
+   * <center><code>
+   * Properties.getProperties(ListProperty.class).getProperties(int.class).getPropertyNames()
+   * </code></center>
+   * <br>
+   * liefert z.B. die Namen aller Listen-Eigenschaften eines Objekts, die
+   * <code>int</code>-Werte aufnehmen koennen.<br>
+   * <b>Bemerke:</b><br>
+   * Wenn das Objekt keine Eigenschaften des angegebenen Typs besitzt, sollte
+   * eine leere Property-Menge (z.B. {@link PropertySet}) zurueckgegeben werden
+   * und <b>nicht</b> <code>null</code>!
+   */
+  public Properties getProperties(Class type);
+
+  /**
+   * Liefert die Namen aller Eigenschaften des Objekts.
+   */
+  public String[] getPropertyNames();
+
+  /**
+   * Liefert die Typen aller Eigenschaften des Objekts.
+   */
+  public PropertyType[] getPropertyTypes();
+
+  /**
+   * Liefert eine Eigenschaft des Objekts.
+   * @param name Name der Eigenschaft
+   * @return <code>null</code> falls das Objekt keine Eigenschaft mit dem
+   *         Namen besitzt
+   */
+  public Property getProperty(String name);
+
+  /**
+   * Prueft, ob das Objekt eine bestimmte Eigenschaft besitzt.
+   */
+  public boolean containsProperty(String name);
+}

Modified: trunk/src/schmitzm/data/property/Property.java
===================================================================
--- trunk/src/schmitzm/data/property/Property.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/property/Property.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,14 +1,32 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package schmitzm.data.property;
 
 import schmitzm.data.event.AbstractObjectTraceable;

Modified: trunk/src/schmitzm/data/property/PropertyException.java
===================================================================
--- trunk/src/schmitzm/data/property/PropertyException.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/property/PropertyException.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,47 +1,65 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data.property;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+/**
+ * Diese Exception wird immer dann geworfen, wenn ein Fehler mit Objekt-Eigenschaften
+ * ({@link Property Properties}) auftritt.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class PropertyException extends RuntimeException {
+  private Property prop = null;
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+  /**
+   * Erzeugt einen neuen Fehler.
+   * @param p       betroffene Eigenschaft
+   * @param message Fehlermeldung
+   */
+  public PropertyException(Property p, String message) {
+    super(message);
+    this.prop = p;
+  }
 
-package schmitzm.data.property;
-
-/**
- * Diese Exception wird immer dann geworfen, wenn ein Fehler mit Objekt-Eigenschaften
- * ({@link Property Properties}) auftritt.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class PropertyException extends RuntimeException {
-  private Property prop = null;
-
-  /**
-   * Erzeugt einen neuen Fehler.
-   * @param p       betroffene Eigenschaft
-   * @param message Fehlermeldung
-   */
-  public PropertyException(Property p, String message) {
-    super(message);
-    this.prop = p;
-  }
-
-  /**
-   * Erzeugt einen neuen Fehler.
-   * @param p betroffene Eigenschaft Zugriff
-   */
-  public PropertyException(Property p) {
-    this(p,"");
-  }
-
-  /**
-   * Liefert die Eigenschaft, fuer die das Problem auftrat.
-   */
-  public Property getProperty() {
-    return prop;
-  }
-}
+  /**
+   * Erzeugt einen neuen Fehler.
+   * @param p betroffene Eigenschaft Zugriff
+   */
+  public PropertyException(Property p) {
+    this(p,"");
+  }
+
+  /**
+   * Liefert die Eigenschaft, fuer die das Problem auftrat.
+   */
+  public Property getProperty() {
+    return prop;
+  }
+}

Modified: trunk/src/schmitzm/data/property/PropertyReadAccess.java
===================================================================
--- trunk/src/schmitzm/data/property/PropertyReadAccess.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/property/PropertyReadAccess.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,198 +1,216 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data.property;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+/**
+ * Diese Klasse stellt ein Recht auf Lesezugriff fuer eine
+ * {@link ValueProperty} dar.
+ * Hierzu implementiert sie die entsprechenden <code>getter</code>-Methoden.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class PropertyReadAccess extends Access {
+  private ValueProperty property       = null;
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+  /**
+   * Erzeugt ein neues Lesezugriffsrecht. Die Anzahl an Zugriffen fuer den
+   * Besitzer ist unbegrenzt.
+   * @param object Instanz von <code>ValueProperty</code> auf die sich das Recht bezieht
+   * @param owner  Besitzer des Rechts
+   * @see schmitzm.data.property.ValueProperty
+   * @exception schmitzm.data.property.AccessViolationException falls das
+   *            angegebene Objekt <b>keine</b> <code>ValueProperty</code> ist
+   */
+  public PropertyReadAccess(Accessible object, Object owner) {
+    this(object,owner,UNLIMITED_ACCESSTIMES);
+  }
 
-package schmitzm.data.property;
-
-/**
- * Diese Klasse stellt ein Recht auf Lesezugriff fuer eine
- * {@link ValueProperty} dar.
- * Hierzu implementiert sie die entsprechenden <code>getter</code>-Methoden.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class PropertyReadAccess extends Access {
-  private ValueProperty property       = null;
-
-  /**
-   * Erzeugt ein neues Lesezugriffsrecht. Die Anzahl an Zugriffen fuer den
-   * Besitzer ist unbegrenzt.
-   * @param object Instanz von <code>ValueProperty</code> auf die sich das Recht bezieht
-   * @param owner  Besitzer des Rechts
-   * @see schmitzm.data.property.ValueProperty
-   * @exception schmitzm.data.property.AccessViolationException falls das
-   *            angegebene Objekt <b>keine</b> <code>ValueProperty</code> ist
-   */
-  public PropertyReadAccess(Accessible object, Object owner) {
-    this(object,owner,UNLIMITED_ACCESSTIMES);
-  }
-
-  /**
-   * Erzeugt ein neues Lesezugriffsrecht.
-   * @param object Instanz von <code>ValueProperty</code> auf die sich das Recht bezieht
-   * @param owner  Besitzer des Rechts
-   * @param maxAccessTimes Anzahl an (Methoden-)Zugriffen, die der Rechtebesitzer
-   *                       taetigen darf, bevor das Recht automatisch entzogen wird
-   * @see schmitzm.data.property.ValueProperty
-   * @exception schmitzm.data.property.AccessViolationException falls das
-   *            angegebene Objekt <b>keine</b> <code>ValueProperty</code> ist
-   */
-  public PropertyReadAccess(Accessible object, Object owner, int maxAccessTimes) {
-    super(object,owner,maxAccessTimes);
-    if (!(object instanceof ValueProperty))
-      throw new AccessViolationException(this,this.getClass().getName()+" can only be instantiated for ValueProperties");
-    this.property = (ValueProperty)object;
-  }
-
-  /**
-   * Liefert den/einen Wert der Eigenschaft.<br>
-   * <code>coords</code> spezifizieren (optional) die "Koordinaten", an denen
-   * der Wert in der Eigenschaft zu finden ist.
-   * Fuer skalare Eigenschaften darf/braucht diese Angabe nicht gemacht zu
-   * werden. Fuer Listen und 1-dim. Matrizen (Arrays) darf nur ein Wert
-   * angegeben werden. Fuer mehr-dimensionale Matrizen muessen entsprechend
-   * der Dimension mehr Koordinaten angegeben werden (als einzelne Parameter oder
-   * als ein Array). z.B. fuer 2-dim. Matrix:<br>
-   * <code>getValue(10,13)</code> oder <code>getValue( new int[] {10,13} )</code><br>
-   * <br>
-   * Kann (seit JDK1.5.0) auch genutzt werden, wenn es sich bei der Property um einen
-   * Build-in-Type handelt.
-   * @param coords optionale Koordinaten
-   * @exception schmitzm.data.property.AccessViolationException falls
-   *            das Leserecht auf der Property nicht mehr gueltig ist
-   */
-  public Object getValue(int... coords) {
-    checkDisposed();
-    Object ret = this.property.getValue(coords);
-    incAndCheckMaxAccessTimesReached();
-    return ret;
-  }
-
-  /**
-   * Liefert den/einen Wert der Eigenschaft als <code>char</code>.
-   * Kann nur genutzt werden, wenn der Objekt-Typ ein Build-In-Type ist.
-   * @param coords (optionale) Koordinaten (siehe <code>getValue(..)</code>
-   *               fuer Erlaeuterungen)
-   * @exception java.lang.ClassCastException falls es sich nicht um eine
-   *            <code>char</code>-Property handelt.
-   * @exception schmitzm.data.property.AccessViolationException falls
-   *            das Leserecht auf der Property nicht mehr gueltig ist
-   * @see #getValue(int...)
-   */
-  public char getValueAsChar(int... coords) {
-    return ((Character)getValue(coords)).charValue();
-  }
-
-  /**
-   * Liefert den/einen aktuellen Wert der Eigenschaft als <code>short</code>.
-   * Kann nur genutzt werden, wenn der Objekt-Typ ein Build-In-Type ist.
-   * @param coords (optionale) Koordinaten (siehe <code>getValue(..)</code>
-   *               fuer Erlaeuterungen)
-   * @exception java.lang.ClassCastException falls es sich nicht um eine
-   *            <code>short</code>-Property handelt.
-   * @exception schmitzm.data.property.AccessViolationException falls
-   *            das Leserecht auf der Property nicht mehr gueltig ist
-   * @see #getValue(int...)
-   */
-  public short getValueAsShort(int... coords) {
-    return ((Number)getValue(coords)).shortValue();
-  }
-
-  /**
-   * Liefert den/einen aktuellen Wert der Eigenschaft als <code>byte</code>.
-   * Kann nur genutzt werden, wenn der Objekt-Typ ein Build-In-Type ist.
-   * @param coords (optionale) Koordinaten (siehe <code>getValue(..)</code>
-   *               fuer Erlaeuterungen)
-   * @exception java.lang.ClassCastException falls es sich nicht um eine
-   *            <code>byte</code>-Property handelt.
-   * @exception schmitzm.data.property.AccessViolationException falls
-   *            das Leserecht auf der Property nicht mehr gueltig ist
-   * @see #getValue(int...)
-   */
-  public byte getValueAsByte(int... coords) {
-    return ((Number)getValue(coords)).byteValue();
-  }
-
-  /**
-   * Liefert den/einen aktuellen Wert der Eigenschaft als <code>int</code>.
-   * Kann nur genutzt werden, wenn der Objekt-Typ ein Build-In-Type ist.
-   * @param coords (optionale) Koordinaten (siehe <code>getValue(..)</code>
-   *               fuer Erlaeuterungen)
-   * @exception java.lang.ClassCastException falls es sich nicht um eine
-   *            <code>int</code>-Property handelt.
-   * @exception schmitzm.data.property.AccessViolationException falls
-   *            das Leserecht auf der Property nicht mehr gueltig ist
-   * @see #getValue(int...)
-   */
-  public int getValueAsInt(int... coords) {
-    return ((Number)getValue(coords)).intValue();
-  }
-
-  /**
-   * Liefert den/einen aktuellen Wert der Eigenschaft als <code>long</code>.
-   * Kann nur genutzt werden, wenn der Objekt-Typ ein Build-In-Type ist.
-   * @param coords (optionale) Koordinaten (siehe <code>getValue(..)</code>
-   *               fuer Erlaeuterungen)
-   * @exception java.lang.ClassCastException falls es sich nicht um eine
-   *            <code>long</code>-Property handelt.
-   * @exception schmitzm.data.property.AccessViolationException falls
-   *            das Leserecht auf der Property nicht mehr gueltig ist
-   * @see #getValue(int...)
-   */
-  public long getValueAsLong(int... coords) {
-    return ((Number)getValue(coords)).longValue();
-  }
-
-  /**
-   * Liefert den/einen aktuellen Wert der Eigenschaft als <code>float</code>.
-   * Kann nur genutzt werden, wenn der Objekt-Typ ein Build-In-Type ist.
-   * @param coords (optionale) Koordinaten (siehe <code>getValue(..)</code>
-   *               fuer Erlaeuterungen)
-   * @exception java.lang.ClassCastException falls es sich nicht um eine
-   *            <code>float</code>-Property handelt.
-   * @exception schmitzm.data.property.AccessViolationException falls
-   *            das Leserecht auf der Property nicht mehr gueltig ist
-   * @see #getValue(int...)
-   */
-  public float getValueAsFloat(int... coords) {
-    return ((Number)getValue(coords)).floatValue();
-  }
-
-  /**
-   * Liefert den/einen aktuellen Wert der Eigenschaft als <code>double</code>.
-   * Kann nur genutzt werden, wenn der Objekt-Typ ein Build-In-Type ist.
-   * @param coords (optionale) Koordinaten (siehe <code>getValue(..)</code>
-   *               fuer Erlaeuterungen)
-   * @exception java.lang.ClassCastException falls es sich nicht um eine
-   *            <code>double</code>-Property handelt.
-   * @exception schmitzm.data.property.AccessViolationException falls
-   *            das Leserecht auf der Property nicht mehr gueltig ist
-   * @see #getValue(int...)
-   */
-  public double getValueAsDouble(int... coords) {
-    return ((Number)getValue(coords)).doubleValue();
-  }
-
-  /**
-   * Liefert den/einen aktuellen Wert der Eigenschaft als <code>boolean</code>.
-   * Kann nur genutzt werden, wenn der Objekt-Typ ein Build-In-Type ist.
-   * @param coords (optionale) Koordinaten (siehe <code>getValue(..)</code>
-   *               fuer Erlaeuterungen)
-   * @exception java.lang.ClassCastException falls es sich nicht um eine
-   *            <code>boolean</code>-Property handelt.
-   * @exception schmitzm.data.property.AccessViolationException falls
-   *            das Leserecht auf der Property nicht mehr gueltig ist
-   * @see #getValue(int...)
-   */
-  public boolean getValueAsBoolean(int... coords) {
-    return ((Boolean)getValue(coords)).booleanValue();
-  }
-
-}
+  /**
+   * Erzeugt ein neues Lesezugriffsrecht.
+   * @param object Instanz von <code>ValueProperty</code> auf die sich das Recht bezieht
+   * @param owner  Besitzer des Rechts
+   * @param maxAccessTimes Anzahl an (Methoden-)Zugriffen, die der Rechtebesitzer
+   *                       taetigen darf, bevor das Recht automatisch entzogen wird
+   * @see schmitzm.data.property.ValueProperty
+   * @exception schmitzm.data.property.AccessViolationException falls das
+   *            angegebene Objekt <b>keine</b> <code>ValueProperty</code> ist
+   */
+  public PropertyReadAccess(Accessible object, Object owner, int maxAccessTimes) {
+    super(object,owner,maxAccessTimes);
+    if (!(object instanceof ValueProperty))
+      throw new AccessViolationException(this,this.getClass().getName()+" can only be instantiated for ValueProperties");
+    this.property = (ValueProperty)object;
+  }
+
+  /**
+   * Liefert den/einen Wert der Eigenschaft.<br>
+   * <code>coords</code> spezifizieren (optional) die "Koordinaten", an denen
+   * der Wert in der Eigenschaft zu finden ist.
+   * Fuer skalare Eigenschaften darf/braucht diese Angabe nicht gemacht zu
+   * werden. Fuer Listen und 1-dim. Matrizen (Arrays) darf nur ein Wert
+   * angegeben werden. Fuer mehr-dimensionale Matrizen muessen entsprechend
+   * der Dimension mehr Koordinaten angegeben werden (als einzelne Parameter oder
+   * als ein Array). z.B. fuer 2-dim. Matrix:<br>
+   * <code>getValue(10,13)</code> oder <code>getValue( new int[] {10,13} )</code><br>
+   * <br>
+   * Kann (seit JDK1.5.0) auch genutzt werden, wenn es sich bei der Property um einen
+   * Build-in-Type handelt.
+   * @param coords optionale Koordinaten
+   * @exception schmitzm.data.property.AccessViolationException falls
+   *            das Leserecht auf der Property nicht mehr gueltig ist
+   */
+  public Object getValue(int... coords) {
+    checkDisposed();
+    Object ret = this.property.getValue(coords);
+    incAndCheckMaxAccessTimesReached();
+    return ret;
+  }
+
+  /**
+   * Liefert den/einen Wert der Eigenschaft als <code>char</code>.
+   * Kann nur genutzt werden, wenn der Objekt-Typ ein Build-In-Type ist.
+   * @param coords (optionale) Koordinaten (siehe <code>getValue(..)</code>
+   *               fuer Erlaeuterungen)
+   * @exception java.lang.ClassCastException falls es sich nicht um eine
+   *            <code>char</code>-Property handelt.
+   * @exception schmitzm.data.property.AccessViolationException falls
+   *            das Leserecht auf der Property nicht mehr gueltig ist
+   * @see #getValue(int...)
+   */
+  public char getValueAsChar(int... coords) {
+    return ((Character)getValue(coords)).charValue();
+  }
+
+  /**
+   * Liefert den/einen aktuellen Wert der Eigenschaft als <code>short</code>.
+   * Kann nur genutzt werden, wenn der Objekt-Typ ein Build-In-Type ist.
+   * @param coords (optionale) Koordinaten (siehe <code>getValue(..)</code>
+   *               fuer Erlaeuterungen)
+   * @exception java.lang.ClassCastException falls es sich nicht um eine
+   *            <code>short</code>-Property handelt.
+   * @exception schmitzm.data.property.AccessViolationException falls
+   *            das Leserecht auf der Property nicht mehr gueltig ist
+   * @see #getValue(int...)
+   */
+  public short getValueAsShort(int... coords) {
+    return ((Number)getValue(coords)).shortValue();
+  }
+
+  /**
+   * Liefert den/einen aktuellen Wert der Eigenschaft als <code>byte</code>.
+   * Kann nur genutzt werden, wenn der Objekt-Typ ein Build-In-Type ist.
+   * @param coords (optionale) Koordinaten (siehe <code>getValue(..)</code>
+   *               fuer Erlaeuterungen)
+   * @exception java.lang.ClassCastException falls es sich nicht um eine
+   *            <code>byte</code>-Property handelt.
+   * @exception schmitzm.data.property.AccessViolationException falls
+   *            das Leserecht auf der Property nicht mehr gueltig ist
+   * @see #getValue(int...)
+   */
+  public byte getValueAsByte(int... coords) {
+    return ((Number)getValue(coords)).byteValue();
+  }
+
+  /**
+   * Liefert den/einen aktuellen Wert der Eigenschaft als <code>int</code>.
+   * Kann nur genutzt werden, wenn der Objekt-Typ ein Build-In-Type ist.
+   * @param coords (optionale) Koordinaten (siehe <code>getValue(..)</code>
+   *               fuer Erlaeuterungen)
+   * @exception java.lang.ClassCastException falls es sich nicht um eine
+   *            <code>int</code>-Property handelt.
+   * @exception schmitzm.data.property.AccessViolationException falls
+   *            das Leserecht auf der Property nicht mehr gueltig ist
+   * @see #getValue(int...)
+   */
+  public int getValueAsInt(int... coords) {
+    return ((Number)getValue(coords)).intValue();
+  }
+
+  /**
+   * Liefert den/einen aktuellen Wert der Eigenschaft als <code>long</code>.
+   * Kann nur genutzt werden, wenn der Objekt-Typ ein Build-In-Type ist.
+   * @param coords (optionale) Koordinaten (siehe <code>getValue(..)</code>
+   *               fuer Erlaeuterungen)
+   * @exception java.lang.ClassCastException falls es sich nicht um eine
+   *            <code>long</code>-Property handelt.
+   * @exception schmitzm.data.property.AccessViolationException falls
+   *            das Leserecht auf der Property nicht mehr gueltig ist
+   * @see #getValue(int...)
+   */
+  public long getValueAsLong(int... coords) {
+    return ((Number)getValue(coords)).longValue();
+  }
+
+  /**
+   * Liefert den/einen aktuellen Wert der Eigenschaft als <code>float</code>.
+   * Kann nur genutzt werden, wenn der Objekt-Typ ein Build-In-Type ist.
+   * @param coords (optionale) Koordinaten (siehe <code>getValue(..)</code>
+   *               fuer Erlaeuterungen)
+   * @exception java.lang.ClassCastException falls es sich nicht um eine
+   *            <code>float</code>-Property handelt.
+   * @exception schmitzm.data.property.AccessViolationException falls
+   *            das Leserecht auf der Property nicht mehr gueltig ist
+   * @see #getValue(int...)
+   */
+  public float getValueAsFloat(int... coords) {
+    return ((Number)getValue(coords)).floatValue();
+  }
+
+  /**
+   * Liefert den/einen aktuellen Wert der Eigenschaft als <code>double</code>.
+   * Kann nur genutzt werden, wenn der Objekt-Typ ein Build-In-Type ist.
+   * @param coords (optionale) Koordinaten (siehe <code>getValue(..)</code>
+   *               fuer Erlaeuterungen)
+   * @exception java.lang.ClassCastException falls es sich nicht um eine
+   *            <code>double</code>-Property handelt.
+   * @exception schmitzm.data.property.AccessViolationException falls
+   *            das Leserecht auf der Property nicht mehr gueltig ist
+   * @see #getValue(int...)
+   */
+  public double getValueAsDouble(int... coords) {
+    return ((Number)getValue(coords)).doubleValue();
+  }
+
+  /**
+   * Liefert den/einen aktuellen Wert der Eigenschaft als <code>boolean</code>.
+   * Kann nur genutzt werden, wenn der Objekt-Typ ein Build-In-Type ist.
+   * @param coords (optionale) Koordinaten (siehe <code>getValue(..)</code>
+   *               fuer Erlaeuterungen)
+   * @exception java.lang.ClassCastException falls es sich nicht um eine
+   *            <code>boolean</code>-Property handelt.
+   * @exception schmitzm.data.property.AccessViolationException falls
+   *            das Leserecht auf der Property nicht mehr gueltig ist
+   * @see #getValue(int...)
+   */
+  public boolean getValueAsBoolean(int... coords) {
+    return ((Boolean)getValue(coords)).booleanValue();
+  }
+
+}

Modified: trunk/src/schmitzm/data/property/PropertySet.java
===================================================================
--- trunk/src/schmitzm/data/property/PropertySet.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/property/PropertySet.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,16 +1,34 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data.property;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.data.property;
-
 import java.util.Enumeration;
 import java.util.Hashtable;
 import java.util.Vector;
@@ -21,266 +39,266 @@
 import schmitzm.data.event.Invoker;
 import schmitzm.data.event.ObjectChangeEvent;
 import schmitzm.data.event.ObjectTraceable;
-
-/**
- * Diese Klasse stellt eine Menge an Eigenschaften dar. Die einzelnen Properties
- * werden parallel in einer {@link java.util.Hashtable} und einem
- * {@link java.util.Vector} verwaltet. Die Hashtable dient dazu, die Properties
- * effizient ueber ihren Namen ansprechen zu koennen. Der Vector repraesentiert
- * eine Ordnung und wird deshalb verwendet, wenn alle Eigenschaften
- * angesprochen werden (z.B. {@link #getProperties()} oder {@link #getPropertyNames()}).<br>
- * Zu beachten ist, dass beim Entfernen einer Eigenschaft aus der Menge
- * <b>nicht</b> die komplette Eigenschaft (mittels {@link Property#dispose()})
- * geschlossen wird! Dies bietet den Vorteil dass
- * eine Eigenschaft einfach von einer Menge in eine andere verschoben werden kann.
- * Soll eine Eigenschaft (und vor allem ihre Ressourcen) komplett freigegeben
- * werden, muss dies manuell geschehen. Hierfuer liefern die remove-Methoden eine
- * Referenz auf die entfernte Eigenschaft zurueck.<br>
- * <code>PropertySet</code> implementiert das Interface {@link ObjectTraceable},
- * so dass Aenderungen an der Menge durch Listener verfolgt werden koennen.
- * Es werden jedoch <b>keine</b> Aenderungen an den in der Menge enthaltenen
- * Eigenschaften propagiert, sondern nur Aenderungen an der Eigenschaftsmenge
- * selbst, also Hinzufuegen oder Entfernen einer Property. In beiden Faellen
- * wird ein {@link ObjectChangeEvent} geworfen, wobei entweder
- * {@link ObjectChangeEvent#getNewValue()} (beim Entfernen) oder {@link ObjectChangeEvent#getOldValue()}
- * (beim Hinzufuegen) <code>null</code> liefert.
- * @see schmitzm.data.property.Property
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class PropertySet extends AbstractObjectTraceable implements DynamicProperties, Cloneable{
-  private Hashtable contentHash = null;
-  private Vector    contentVec  = null;
-
-  /**
-   * Erzeugt eine leere Menge von Eigenschaften aus einer Vorlage. Es wird jedoch
-   * nur die Struktur der Vorlage kopiert, <b>nicht</b> die darin enthaltenen
-   * Eigenschaften!!
-   * @param propSet Vorlage fuer die Property-Menge
-   */
-  public PropertySet(PropertySet propSet) {
-    this.contentHash =  (Hashtable)propSet.contentHash.clone();
-    this.contentVec  =  (Vector)propSet.contentVec.clone();
-  }
-
-  /**
-   * Erzeugt eine leere Menge von Eigenschaften.
-   */
-  public PropertySet() {
-    this.contentHash = new Hashtable();
-    this.contentVec  = new Vector();
-  }
-
-  /**
-   * Erzeugt eine Kopie der Menge. Dabei wird jedoch nicht der Inhalt - also
-   * die Properties selbst - kopiert, sondern nur das Hashtable-Objekt!!
-   */
-  public Object clone() {
-    return new PropertySet(this);
-  }
-
-  /**
-   * Liefert die Anzahl an Eigenschaften.
-   */
-  public int getPropertyCount() {
-    return contentVec.size();
-  }
-
-  /**
-   * Liefert die Eigenschaften der Menge als Array.
-   */
-  public Property[] getProperties() {
-//    return (Property[])contentHash.values().toArray(new Property[] {});
-    return (Property[])contentVec.toArray(new Property[] {});
-  }
-
-  /**
-   * Liefert alle Eigenschaften, die einem bestimmten
-   * Typ angehoeren. Als Typ kann sowohl ein bestimmter <code>Property</code>-Untertyp
-   * angegeben werden (z.B. {@link ListProperty}), als auch ein Objekt-Typ (Typ
-   * den eine Property aufnehmen kann; z.B. <code>int.class</code>).<br>
-   * Da die Methode wiederum eine <code>Properties</code>-Instanz liefert,
-   * lassen sich recht einfach verschiedene Filter hintereinander anwenden:<br>
-   * <br>
-   * <center><code>
-   * Properties.getProperties(ListProperty.class).getProperties(int.class).getPropertyNames()
-   * </code></center>
-   * <br>
-   * liefert z.B. die Namen aller Listen-Eigenschaften, die <code>int</code>-Werte
-   * aufnehmen koennen.
-   */
-  public Properties getProperties(Class type) {
-    PropertySet set = new PropertySet();
-    for(Enumeration e=contentVec.elements();e.hasMoreElements();) {
-      Property p = (Property)e.nextElement();
-      // Ist der angegebene Typ eine Property (oder ein Untertyp),
-      // wird direkt auf die Art der Property geprueft (1), ansonsten auf den
-      // Typ, den die Property beinhalten kann (2)
-      if ( Property.class.isAssignableFrom(type) ) {
-        // (1) type Superklasse der Property-Art?
-        if ( type.isAssignableFrom( p.getClass() ) )
-          set.addProperty(p);
-      } else {
-        // (2) type Superklasse des Property-Typs?
-        if ( type.isAssignableFrom( p.getType() ) )
-          set.addProperty(p);
-      }
-    }
-
-    return set;
-  }
-
-  /**
-   * Liefert die Namen aller Eigenschaften.
-   */
-  public String[] getPropertyNames() {
-//    return (String[])content.keySet().toArray(new String[0]);
-    String[] name = new String[ getPropertyCount() ];
-    Enumeration e = contentVec.elements();
-    for(int i=0; e.hasMoreElements(); i++)
-      name[i] = ((Property)e.nextElement()).getName();
-    return name;
-  }
-
-  /**
-   * Liefert die Typen aller Eigenschaften.
-   */
-  public PropertyType[] getPropertyTypes() {
-    PropertyType[]  type = new PropertyType[ getPropertyCount() ];
-    Enumeration e = contentVec.elements();
-    for(int i=0; e.hasMoreElements(); i++)
-      type[i] = ((Property)e.nextElement()).getPropertyType();
-    return type;
-  }
-
-  /**
-   * Liefert eine bestimmte Eigenschaft der Menge.
-   * @param name Name der Eigenschaft
-   * @return <code>null</code> falls die Menge keine Eigenschaft dieses
-   *         Namens enthaelt
-   */
-  public Property getProperty(String name) {
-    return (Property)contentHash.get(name);
-  }
-
-  /**
-   * Prueft, ob die Menge eine bestimmte Eigenschaft enthaelt.
-   * @param name Name der Eigenschaft
-   */
-  public boolean containsProperty(String name) {
-    return getProperty(name)!=null;
-  }
-
-  /**
-   * Fuegt der Menge eine Eigenschaft hinzu. Dabei wird auf Eindeutigkeit
-   * des Namens geachtet!
-   * @param prop Eigenschaft
-   * @exception schmitzm.data.property.PropertyException falls bereits
-   *            eine Eigenschaft dieses Namens in der Menge vorhanden ist
-   */
-  public void addProperty(Property prop) {
-    if ( containsProperty(prop.getName()) )
-      throw new PropertyException(prop,"PropertySet already contains a Property named '".concat(prop.getName()).concat("'"));
-    contentHash.put(prop.getName(),prop);
-    contentVec.add(prop);
-    fireEvent(new ObjectChangeEvent(new Invoker(this),null,prop));
-  }
-
-  /**
-   * Entfernt eine Eigenschaft aus der Menge.
-   * @param name Name der Eigenschaft
-   * @return Die entferne Eigenschaft oder <code>null</code>, falls das
-   *         die Menge keine Eigenschaft mit dem Namen enthaelt
-   */
-  public Property removeProperty(String name) {
-    Property prop = (Property)contentHash.remove(name);
-    contentVec.remove(prop);
-    fireEvent(new ObjectChangeEvent(new Invoker(this),prop,null));
-    return prop;
-  }
-
-  /**
-   * Entfernt eine Eigenschaft aus der Menge.
-   * Falls die Menge eine solche Eigenschaft nicht besitzt, passiert nichts.
-   * @param prop zu entfernende Eigenschaft
-   * @return Die entferne Eigenschaft oder <code>null</code> falls das Objekt
-   *         die Eigenschaft nicht besitzt
-   */
-  public Property removeProperty(Property prop) {
-    return removeProperty(prop.getName());
-  }
-
-  /**
-   * Entfernt Eigenschaften aus der Menge. Falls die Menge eine dieser
-   * Eigenschaften nicht enthaelt, passiert fuer die entsprechende Eigenschaft
-   * nichts.
-   * @param prop zu entfernende Eigenschaft
-   * @return Die entfernten Eigenschaften (kann eine leere Eigenschaftsmenge
-   *         sein, wenn die Menge <u>keine</u> der uebergebenen Eigenschaften
-   *         besitzt.
-   */
-  public Properties removeProperties(Properties prop) {
-    Property    p   = null;
-    PropertySet set = new PropertySet();
-    for (int i=0; i<prop.getProperties().length; i++)
-      if ( (p = removeProperty(prop.getProperties()[i]))!=null )
-        set.addProperty(p);
-    return set;
-  }
-
-  ///////////////////////////////////////////////////////////////////
-  // Implementierung von ObjectStructure
-  ///////////////////////////////////////////////////////////////////
-  /**
-   * Liefert <code>false</code>.
-   */
-  public boolean isStructureNamed() {
-    return false;
-  }
-
-  /**
-   * Liefert <code>null</code>.
-   */
-  public String getStructureName() {
-    return null;
-  }
-
-  /**
-   * Liefert die Anzah1 an Properties in der Menge.
-   * @see #getPropertyCount()
-   */
-  public int getAttrCount() {
-    return getPropertyCount();
-  }
-
-  /**
-   * Liefert eine Liste, die genau so viele Elemente enthaelt, wie die
-   * Eigenschaftsmenge Propertys hat. Alle Listen-Elemente sind vom Typ
-   * {@link ObjectStructure}.
-   */
-  public Enumeration<ObjectStructure> getAttrTypes() {
-    return contentVec.elements();
-  }
-
-  /**
-   * Vergleicht die Struktur der Property mit einer anderen auf Gleichheit.
-   * @param object eine anderes {@link ObjectStructure}-Objekt
-   * @return <code>false</code> falls das uebergebene Objekt keine
-   *         {@link ObjectStructure} ist
-   * @see ValuePropertyType#equalsInStructure(Object)
-   */
-  public boolean equalsInStructure(Object object) {
-    if ( !(object instanceof ObjectStructure) )
-      return false;
-    return ObjectStructureUtil.compareObjectStructures(this,(ObjectStructure)object) == ObjectStructureUtil.EQUAL;
-  }
-
-  /**
-   * Liefert <code>false</code>, da eine Eigenschaftsmenge von jeder Eigenschaft
-   * immer nur eine Instanz enthaelt.
-   */
-  public boolean containsMultipleValues() {
-    return false;
-  }
-
-}
+
+/**
+ * Diese Klasse stellt eine Menge an Eigenschaften dar. Die einzelnen Properties
+ * werden parallel in einer {@link java.util.Hashtable} und einem
+ * {@link java.util.Vector} verwaltet. Die Hashtable dient dazu, die Properties
+ * effizient ueber ihren Namen ansprechen zu koennen. Der Vector repraesentiert
+ * eine Ordnung und wird deshalb verwendet, wenn alle Eigenschaften
+ * angesprochen werden (z.B. {@link #getProperties()} oder {@link #getPropertyNames()}).<br>
+ * Zu beachten ist, dass beim Entfernen einer Eigenschaft aus der Menge
+ * <b>nicht</b> die komplette Eigenschaft (mittels {@link Property#dispose()})
+ * geschlossen wird! Dies bietet den Vorteil dass
+ * eine Eigenschaft einfach von einer Menge in eine andere verschoben werden kann.
+ * Soll eine Eigenschaft (und vor allem ihre Ressourcen) komplett freigegeben
+ * werden, muss dies manuell geschehen. Hierfuer liefern die remove-Methoden eine
+ * Referenz auf die entfernte Eigenschaft zurueck.<br>
+ * <code>PropertySet</code> implementiert das Interface {@link ObjectTraceable},
+ * so dass Aenderungen an der Menge durch Listener verfolgt werden koennen.
+ * Es werden jedoch <b>keine</b> Aenderungen an den in der Menge enthaltenen
+ * Eigenschaften propagiert, sondern nur Aenderungen an der Eigenschaftsmenge
+ * selbst, also Hinzufuegen oder Entfernen einer Property. In beiden Faellen
+ * wird ein {@link ObjectChangeEvent} geworfen, wobei entweder
+ * {@link ObjectChangeEvent#getNewValue()} (beim Entfernen) oder {@link ObjectChangeEvent#getOldValue()}
+ * (beim Hinzufuegen) <code>null</code> liefert.
+ * @see schmitzm.data.property.Property
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class PropertySet extends AbstractObjectTraceable implements DynamicProperties, Cloneable{
+  private Hashtable contentHash = null;
+  private Vector    contentVec  = null;
+
+  /**
+   * Erzeugt eine leere Menge von Eigenschaften aus einer Vorlage. Es wird jedoch
+   * nur die Struktur der Vorlage kopiert, <b>nicht</b> die darin enthaltenen
+   * Eigenschaften!!
+   * @param propSet Vorlage fuer die Property-Menge
+   */
+  public PropertySet(PropertySet propSet) {
+    this.contentHash =  (Hashtable)propSet.contentHash.clone();
+    this.contentVec  =  (Vector)propSet.contentVec.clone();
+  }
+
+  /**
+   * Erzeugt eine leere Menge von Eigenschaften.
+   */
+  public PropertySet() {
+    this.contentHash = new Hashtable();
+    this.contentVec  = new Vector();
+  }
+
+  /**
+   * Erzeugt eine Kopie der Menge. Dabei wird jedoch nicht der Inhalt - also
+   * die Properties selbst - kopiert, sondern nur das Hashtable-Objekt!!
+   */
+  public Object clone() {
+    return new PropertySet(this);
+  }
+
+  /**
+   * Liefert die Anzahl an Eigenschaften.
+   */
+  public int getPropertyCount() {
+    return contentVec.size();
+  }
+
+  /**
+   * Liefert die Eigenschaften der Menge als Array.
+   */
+  public Property[] getProperties() {
+//    return (Property[])contentHash.values().toArray(new Property[] {});
+    return (Property[])contentVec.toArray(new Property[] {});
+  }
+
+  /**
+   * Liefert alle Eigenschaften, die einem bestimmten
+   * Typ angehoeren. Als Typ kann sowohl ein bestimmter <code>Property</code>-Untertyp
+   * angegeben werden (z.B. {@link ListProperty}), als auch ein Objekt-Typ (Typ
+   * den eine Property aufnehmen kann; z.B. <code>int.class</code>).<br>
+   * Da die Methode wiederum eine <code>Properties</code>-Instanz liefert,
+   * lassen sich recht einfach verschiedene Filter hintereinander anwenden:<br>
+   * <br>
+   * <center><code>
+   * Properties.getProperties(ListProperty.class).getProperties(int.class).getPropertyNames()
+   * </code></center>
+   * <br>
+   * liefert z.B. die Namen aller Listen-Eigenschaften, die <code>int</code>-Werte
+   * aufnehmen koennen.
+   */
+  public Properties getProperties(Class type) {
+    PropertySet set = new PropertySet();
+    for(Enumeration e=contentVec.elements();e.hasMoreElements();) {
+      Property p = (Property)e.nextElement();
+      // Ist der angegebene Typ eine Property (oder ein Untertyp),
+      // wird direkt auf die Art der Property geprueft (1), ansonsten auf den
+      // Typ, den die Property beinhalten kann (2)
+      if ( Property.class.isAssignableFrom(type) ) {
+        // (1) type Superklasse der Property-Art?
+        if ( type.isAssignableFrom( p.getClass() ) )
+          set.addProperty(p);
+      } else {
+        // (2) type Superklasse des Property-Typs?
+        if ( type.isAssignableFrom( p.getType() ) )
+          set.addProperty(p);
+      }
+    }
+
+    return set;
+  }
+
+  /**
+   * Liefert die Namen aller Eigenschaften.
+   */
+  public String[] getPropertyNames() {
+//    return (String[])content.keySet().toArray(new String[0]);
+    String[] name = new String[ getPropertyCount() ];
+    Enumeration e = contentVec.elements();
+    for(int i=0; e.hasMoreElements(); i++)
+      name[i] = ((Property)e.nextElement()).getName();
+    return name;
+  }
+
+  /**
+   * Liefert die Typen aller Eigenschaften.
+   */
+  public PropertyType[] getPropertyTypes() {
+    PropertyType[]  type = new PropertyType[ getPropertyCount() ];
+    Enumeration e = contentVec.elements();
+    for(int i=0; e.hasMoreElements(); i++)
+      type[i] = ((Property)e.nextElement()).getPropertyType();
+    return type;
+  }
+
+  /**
+   * Liefert eine bestimmte Eigenschaft der Menge.
+   * @param name Name der Eigenschaft
+   * @return <code>null</code> falls die Menge keine Eigenschaft dieses
+   *         Namens enthaelt
+   */
+  public Property getProperty(String name) {
+    return (Property)contentHash.get(name);
+  }
+
+  /**
+   * Prueft, ob die Menge eine bestimmte Eigenschaft enthaelt.
+   * @param name Name der Eigenschaft
+   */
+  public boolean containsProperty(String name) {
+    return getProperty(name)!=null;
+  }
+
+  /**
+   * Fuegt der Menge eine Eigenschaft hinzu. Dabei wird auf Eindeutigkeit
+   * des Namens geachtet!
+   * @param prop Eigenschaft
+   * @exception schmitzm.data.property.PropertyException falls bereits
+   *            eine Eigenschaft dieses Namens in der Menge vorhanden ist
+   */
+  public void addProperty(Property prop) {
+    if ( containsProperty(prop.getName()) )
+      throw new PropertyException(prop,"PropertySet already contains a Property named '".concat(prop.getName()).concat("'"));
+    contentHash.put(prop.getName(),prop);
+    contentVec.add(prop);
+    fireEvent(new ObjectChangeEvent(new Invoker(this),null,prop));
+  }
+
+  /**
+   * Entfernt eine Eigenschaft aus der Menge.
+   * @param name Name der Eigenschaft
+   * @return Die entferne Eigenschaft oder <code>null</code>, falls das
+   *         die Menge keine Eigenschaft mit dem Namen enthaelt
+   */
+  public Property removeProperty(String name) {
+    Property prop = (Property)contentHash.remove(name);
+    contentVec.remove(prop);
+    fireEvent(new ObjectChangeEvent(new Invoker(this),prop,null));
+    return prop;
+  }
+
+  /**
+   * Entfernt eine Eigenschaft aus der Menge.
+   * Falls die Menge eine solche Eigenschaft nicht besitzt, passiert nichts.
+   * @param prop zu entfernende Eigenschaft
+   * @return Die entferne Eigenschaft oder <code>null</code> falls das Objekt
+   *         die Eigenschaft nicht besitzt
+   */
+  public Property removeProperty(Property prop) {
+    return removeProperty(prop.getName());
+  }
+
+  /**
+   * Entfernt Eigenschaften aus der Menge. Falls die Menge eine dieser
+   * Eigenschaften nicht enthaelt, passiert fuer die entsprechende Eigenschaft
+   * nichts.
+   * @param prop zu entfernende Eigenschaft
+   * @return Die entfernten Eigenschaften (kann eine leere Eigenschaftsmenge
+   *         sein, wenn die Menge <u>keine</u> der uebergebenen Eigenschaften
+   *         besitzt.
+   */
+  public Properties removeProperties(Properties prop) {
+    Property    p   = null;
+    PropertySet set = new PropertySet();
+    for (int i=0; i<prop.getProperties().length; i++)
+      if ( (p = removeProperty(prop.getProperties()[i]))!=null )
+        set.addProperty(p);
+    return set;
+  }
+
+  ///////////////////////////////////////////////////////////////////
+  // Implementierung von ObjectStructure
+  ///////////////////////////////////////////////////////////////////
+  /**
+   * Liefert <code>false</code>.
+   */
+  public boolean isStructureNamed() {
+    return false;
+  }
+
+  /**
+   * Liefert <code>null</code>.
+   */
+  public String getStructureName() {
+    return null;
+  }
+
+  /**
+   * Liefert die Anzah1 an Properties in der Menge.
+   * @see #getPropertyCount()
+   */
+  public int getAttrCount() {
+    return getPropertyCount();
+  }
+
+  /**
+   * Liefert eine Liste, die genau so viele Elemente enthaelt, wie die
+   * Eigenschaftsmenge Propertys hat. Alle Listen-Elemente sind vom Typ
+   * {@link ObjectStructure}.
+   */
+  public Enumeration<ObjectStructure> getAttrTypes() {
+    return contentVec.elements();
+  }
+
+  /**
+   * Vergleicht die Struktur der Property mit einer anderen auf Gleichheit.
+   * @param object eine anderes {@link ObjectStructure}-Objekt
+   * @return <code>false</code> falls das uebergebene Objekt keine
+   *         {@link ObjectStructure} ist
+   * @see ValuePropertyType#equalsInStructure(Object)
+   */
+  public boolean equalsInStructure(Object object) {
+    if ( !(object instanceof ObjectStructure) )
+      return false;
+    return ObjectStructureUtil.compareObjectStructures(this,(ObjectStructure)object) == ObjectStructureUtil.EQUAL;
+  }
+
+  /**
+   * Liefert <code>false</code>, da eine Eigenschaftsmenge von jeder Eigenschaft
+   * immer nur eine Instanz enthaelt.
+   */
+  public boolean containsMultipleValues() {
+    return false;
+  }
+
+}

Modified: trunk/src/schmitzm/data/property/PropertyType.java
===================================================================
--- trunk/src/schmitzm/data/property/PropertyType.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/property/PropertyType.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,78 +1,96 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data.property;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+import schmitzm.temp.BaseTypeUtil;
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+/**
+ * Diese Klasse stellt allgemein den (strukturellen) Typ einer Eigenschaft dar.
+ * Sie selbst implementiert lediglich die Speicherung eines Klassennamens.
+ * Entscheidender sind die abgeleiteten Untertypen:<br>
+ * Fuer alle Wert-Eigenschaften ist im {@linkplain ValuePropertyType Typ} z.B.
+ * (falls vorhanden) die Unterstruktur gespeichert.
+ * @see ValuePropertyType
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public abstract class PropertyType {
+  /**
+   * Speichert den eigentlichen Typ der Property.
+   */
+  protected Class type = null;
 
-package schmitzm.data.property;
-
-import schmitzm.temp.BaseTypeUtil;
-
-/**
- * Diese Klasse stellt allgemein den (strukturellen) Typ einer Eigenschaft dar.
- * Sie selbst implementiert lediglich die Speicherung eines Klassennamens.
- * Entscheidender sind die abgeleiteten Untertypen:<br>
- * Fuer alle Wert-Eigenschaften ist im {@linkplain ValuePropertyType Typ} z.B.
- * (falls vorhanden) die Unterstruktur gespeichert.
- * @see ValuePropertyType
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public abstract class PropertyType {
-  /**
-   * Speichert den eigentlichen Typ der Property.
-   */
-  protected Class type = null;
-
-  /**
-   * Erzeugt einen neuen Eigenschaftstyp
-   * @param type Objekt-Typ den die Eigenschaft aufnehmen kann
-   */
-  public PropertyType(Class type) {
-    this.type = type;
-  }
-
-  /**
-   * Liefert den Typ, den die Eigenschaft aufnehmen kann.
-   */
-  public Class getType() {
-    return this.type;
-  }
-
-  /**
-   * Checkt, ob die Property einen Wert vom Typ <code>type</code> aufnehmen
-   * kann. Dies ist der Fall, wenn <code>type</code> dieselbe oder eine
-   * Subklasse des Property-Typs ist.<br>
-   * Ausserdem gelten fuer Build-In-Types auch die entsprechenden Objekte
-   * (z.B. <code>Integer</code>-Instanz fuer in <code>int</code>-Property)
-   * als gueltig.
-   * @see schmitzm.data.property.Property#isValid(Class)
-   * @see schmitzm.temp.BaseTypeUtil#isBuildInType(Class)
-   * @see schmitzm.temp.BaseTypeUtil#isEquivalent(Class,Class)
-   */
-  public boolean isValid(Class type) {
-    return getType().isAssignableFrom(type) ||
-           BaseTypeUtil.isBuildInType(getType()) && BaseTypeUtil.isEquivalent(getType(),type);
-//    return getType().equals(char.class)    && Character.class.isAssignableFrom(type) ||
-//           getType().equals(short.class)   && Short.class.isAssignableFrom(type) ||
-//           getType().equals(byte.class)    && Byte.class.isAssignableFrom(type) ||
-//           getType().equals(int.class)     && Integer.class.isAssignableFrom(type) ||
-//           getType().equals(long.class)    && Long.class.isAssignableFrom(type) ||
-//           getType().equals(float.class)   && Float.class.isAssignableFrom(type) ||
-//           getType().equals(double.class)  && Double.class.isAssignableFrom(type) ||
-//           getType().equals(boolean.class) && Boolean.class.isAssignableFrom(type) ||
-//           getType().isAssignableFrom(type);
-  }
-
-  /**
-   * Liefert den Namen der Typ-Klasse als Beschreibung des Eigenschaftstyp.
-   */
-  public String toString() {
-    return getType().getName();
-  }
-}
+  /**
+   * Erzeugt einen neuen Eigenschaftstyp
+   * @param type Objekt-Typ den die Eigenschaft aufnehmen kann
+   */
+  public PropertyType(Class type) {
+    this.type = type;
+  }
+
+  /**
+   * Liefert den Typ, den die Eigenschaft aufnehmen kann.
+   */
+  public Class getType() {
+    return this.type;
+  }
+
+  /**
+   * Checkt, ob die Property einen Wert vom Typ <code>type</code> aufnehmen
+   * kann. Dies ist der Fall, wenn <code>type</code> dieselbe oder eine
+   * Subklasse des Property-Typs ist.<br>
+   * Ausserdem gelten fuer Build-In-Types auch die entsprechenden Objekte
+   * (z.B. <code>Integer</code>-Instanz fuer in <code>int</code>-Property)
+   * als gueltig.
+   * @see schmitzm.data.property.Property#isValid(Class)
+   * @see schmitzm.temp.BaseTypeUtil#isBuildInType(Class)
+   * @see schmitzm.temp.BaseTypeUtil#isEquivalent(Class,Class)
+   */
+  public boolean isValid(Class type) {
+    return getType().isAssignableFrom(type) ||
+           BaseTypeUtil.isBuildInType(getType()) && BaseTypeUtil.isEquivalent(getType(),type);
+//    return getType().equals(char.class)    && Character.class.isAssignableFrom(type) ||
+//           getType().equals(short.class)   && Short.class.isAssignableFrom(type) ||
+//           getType().equals(byte.class)    && Byte.class.isAssignableFrom(type) ||
+//           getType().equals(int.class)     && Integer.class.isAssignableFrom(type) ||
+//           getType().equals(long.class)    && Long.class.isAssignableFrom(type) ||
+//           getType().equals(float.class)   && Float.class.isAssignableFrom(type) ||
+//           getType().equals(double.class)  && Double.class.isAssignableFrom(type) ||
+//           getType().equals(boolean.class) && Boolean.class.isAssignableFrom(type) ||
+//           getType().isAssignableFrom(type);
+  }
+
+  /**
+   * Liefert den Namen der Typ-Klasse als Beschreibung des Eigenschaftstyp.
+   */
+  public String toString() {
+    return getType().getName();
+  }
+}

Modified: trunk/src/schmitzm/data/property/PropertyUtil.java
===================================================================
--- trunk/src/schmitzm/data/property/PropertyUtil.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/property/PropertyUtil.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,323 +1,341 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.data.property;
-
-import java.util.Vector;
-
-import schmitzm.lang.LangUtil;
-import schmitzm.temp.BaseTypeUtil;
-
-/**
- * Diese Klasse beinhaltet statische Hilfsmethoden fuer das Arbeiten mit
- * {@link Property} und {@link Properties}.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class PropertyUtil {
-
-  /**
-   * Liefert eine Eigenschaft eines {@link Properties}-Objekt.
-   * Enthaelt das {@link Properties}-Objekt keine Eigenschaft mit dem
-   * angegebenen Namen, wird dieser sukzessive verkuerzt (Punkt-Notation)
-   * bis im Objekt eine entsprechende Eigenschaft gefunden wird.
-   * In diesem Fall muss es sich beim Wert dieser Eigenschaft
-   * wiederum um ein {@link Properties}-Objekt handeln, um den "abgeschnittenen"
-   * Teil des Eigenschaft-Names rekursiv zu verarbeiten.
-   * @param propObject {@link Properties}-Objekt
-   * @param propSuffix Name der Eigenschaft (bzw. mehrere Eigenschaften
-   *                   durch "." getrennt)
-   * @return {@code null} wenn die Eigenschaft nicht gefunden werden kann
-   */
-  public static Property getProperty(Properties propObject, String propSuffix) {
-    return getProperty(propObject, propSuffix, '.');
-  }
-
-  /**
-   * Liefert den Wert eine Eigenschaft. Enthaelt das {@link Properties}-Objekt
-   * keine Eigenschaft mit dem angegebenen Namen, wird dieser sukzessive
-   * verkuerzt (Punkt-Notation) bis im Objekt eine entsprechende Eigenschaft
-   * gefunden wird. In diesem Fall muss es sich beim Wert dieser Eigenschaft
-   * wiederum um ein {@link Properties}-Objekt handeln, um den "abgeschnittenen"
-   * Teil des Eigenschaft-Names rekursiv zu verarbeiten.
-   * @param propObject {@link Properties}-Objekt
-   * @param propSuffix Name der Eigenschaft (bzw. mehrere Eigenschaften
-   *                   getrennt durch das {@code sep}-Zeichen)
-   * @param sep        Trenn-Zeichen, mit dem in {@link propSuffix} mehere Eigenschaften
-   *                   von einander getrennt sind
-   * @return {@code null} wenn die Eigenschaft nicht gefunden werden kann
-   */
-  public static Property getProperty(Properties propObject, String propSuffix, char sep) {
-    if ( propSuffix == null )
-      propSuffix = "";
-
-    String propName = propSuffix;
-    int[]  arrayCoord = new int[0];
-    propSuffix = "";
-    while ( !propName.equals("") ) {
-      Property prop = propObject.getProperty(propName);
-      if ( prop == null ) {
-        arrayCoord = getArrayCoordinates(propName);
-        if ( arrayCoord.length > 0 ) {
-          // cut the array coordinates
-          propName = cutArrayCoordinates(propName);
-          prop     = propObject.getProperty(propName);
-        }
-      }
-      // Property found
-      if ( prop != null ) {
-        // no more property names exist >> the object is the requested property (Juhuuuu!)
-        if ( propSuffix.equals("") )
-          return prop;
-
-        // more property names exist >> property must be a ScalarProperty containing
-        //                              a Properties to perform the property suffix
-        if ( prop instanceof ValueProperty ) {
-          Object propValue = ((ValueProperty)prop).getOneTimeReadAccess().getValue(arrayCoord);
-          if ( propValue instanceof Properties )
-            return getProperty((Properties)propValue, propSuffix, sep);
-        }
-      }
-
-      // cut at last "." and try the prefix as property name
-      int tLastDotIdx = propName.lastIndexOf(sep);
-      if ( !propSuffix.equals("") )
-        propSuffix += sep;
-      propSuffix += propName.substring(tLastDotIdx+1);
-      propName   =  tLastDotIdx > 0 ? propName.substring(0,tLastDotIdx) : "";
-    }
-    // Property not found in object
-    return null;
-  }
-
-  /**
-   * Ermittelt die am Ende eines Strings in runden Klammern spezifierten
-   * Koordinaten.
-   * @param objectSpec ein String
-   * @return int[0], wenn der String keine Klammerung am Ende enthaelt.
-   */
-  public static int[] getArrayCoordinates(String objectSpec) {
-    objectSpec = objectSpec.trim();
-    int[] arrayCoord = new int[0];
-    if ( objectSpec.endsWith(")") && objectSpec.contains("(")) {
-      int openIdx = objectSpec.lastIndexOf("(");
-      String[] arrayCoordStr = objectSpec.substring(openIdx+1,objectSpec.length()-1).split(",");
-      arrayCoord = new int[arrayCoordStr.length];
-      for (int i=0; i<arrayCoord.length; i++)
-        arrayCoord[i] = Integer.parseInt(arrayCoordStr[i].trim());
-    }
-    return arrayCoord;
-  }
-
-  /**
-   * Entfernt eine etwaige Koordinaten-Definition (in runden Klammern) am
-   * Ende eines Strings.
-   * @param objectSpec ein String
-   * @return den original String, wenn dieser keine Koordinaten-Definition
-   *         enthaelt
-   */
-  public static String cutArrayCoordinates(String objectSpec) {
-    if ( objectSpec.endsWith(")") && objectSpec.contains("("))
-      return objectSpec.substring(0, objectSpec.lastIndexOf("("));
-    return objectSpec;
-  }
-
-
-  /**
-   * Wraps a {@link Property} to an appropriate java object.
-   * <ul>
-   *   <li>{@link ScalarProperty}: wrapped to its (single) value</li>
-   *   <li>{@link ListProperty}: wrapped to an appropriate {@link Vector} which
-   *                             contains the {@link ListProperty} values</li>
-   *   <li>{@link MatrixProperty}: wrapped to an appropriate native {@code Object[]..[]}
-   *                               which contains the {@link MatrixProperty} values</li>
-   * </ul>
-   * @param prop   a property
-   * @param coord  <b>if specified, the appropiate element of the {@link ListProperty}
-   *               or {@link MatrixProperty} is returned, instead of the complete
-   *               list or matrix!</b>
-   * @return the Property itself, if no wrap can be performed
-   */
-  public static Object getPropertyValue(Property prop, int... coord) {
-    if ( coord == null )
-      coord = new int[0];
-
-    //*********** ScalarProperty **************
-    if ( prop instanceof ScalarProperty ) {
-      return ((ScalarProperty)prop).getOneTimeReadAccess().getValue();
-    }
-
-    //*********** ListProperty **************
-    if ( prop instanceof ListProperty ) {
-      // if coordinates are given, the list element is returned
-      if (coord.length > 0)
-        return ((ListProperty)prop).getOneTimeReadAccess().getValue(coord);
-      // return all list elements as Vector
-      ListPropertyReadAccess prop_RA = ((ListProperty)prop).getReadAccess(null);
-      Vector vector = new Vector( prop_RA.getCount() );
-      for (int i=0; i<prop_RA.getCount(); i++)
-        vector.add( prop_RA.getValue(i) );
-      prop_RA.release();
-      return vector;
-    }
-
-    //*********** MatrixProperty **************
-    if ( prop instanceof MatrixProperty ) {
-      // if coordinates are given, the matrix element is returned
-      if (coord.length > 0)
-        return ((MatrixProperty)prop).getOneTimeReadAccess().getValue(coord);
-
-      // challenge: MatrixProperty is generic and its dimension and
-      //            data type is not fixed
-      //            --> the creation of the target native array
-      //                must be realised generic too
-      MatrixProperty     matrixProp = (MatrixProperty)prop;
-      PropertyReadAccess prop_RA    = (matrixProp).getReadAccess(null);
-      int[]              dimSizes   = matrixProp.getSize(); // Size of the dimensions
-      Object             array      = LangUtil.createArray( dimSizes );
-      // Calculate the total number of elements in the matrix
-      int elemCount = 1;
-      for ( int dimSize : dimSizes )
-        elemCount *= dimSize;
-
-      // put the elements in the array
-      coord = new int[ dimSizes.length ];
-      for ( int i=0; i<elemCount; i++ ) {
-        // set the element at coordinate tCoord
-        LangUtil.setArrayValue(
-            array,
-            prop_RA.getValue( coord ),
-            coord
-        );
-
-        // increment the coordinate for the element
-        for (int d = 1; d < dimSizes.length; d++)
-          if (++coord[d] < dimSizes[d])
-            break; // Coordinates in dimensionen > d not influenced by the increment
-          else
-            coord[d] = 0; // Initialize coordinate in dimension d and continue
-                          // to increment in dimension d+1 erhoehen
-      }
-      prop_RA.release();
-      return array;
-    }
-
-    return prop;
-  }
-
-  /**
-   * Sets the value of a {@link Property} with an appropriate java object.
-   * <ul>
-   *   <li>{@link ScalarProperty}: sets the property's (single) value to {@code aValue}</li>
-   *   <li>{@link ListProperty}: clears the list and fills it with the
-   *                             elements of {@code aValue} (must be an {@code Object[]}
-   *                             or an {@link Iterable})</li>
-   *   <li>{@link MatrixProperty}: fills the matrix with the elements of
-   *                               {@code aValue} (must be an {@code Object[]})</li>
-   * </ul>
-   * @param prop   a property
-   * @param value  a value the property is set to
-   * @param coord  <b>if specified, only the appropiate element of the {@link ListProperty}
-   *               or {@link MatrixProperty} is set with {@code aValue},
-   *               instead of the complete list or matrix!</b>
-   */
-  public static void setPropertyValue(ValueProperty prop, Object value, int... coord) {
-    if ( coord == null )
-      coord = new int[0];
-
-    //*********** ScalarProperty **************
-    if (prop instanceof ScalarProperty)
-      ((ScalarProperty)prop).getOneTimeWriteAccess().setValue(
-          convertToPropertyType(value, prop.getType())
-      );
-
-    //*********** ListProperty **************
-    if (prop instanceof ListProperty) {
-      // if coordinates are given, the matrix element is set
-      if (coord.length > 0) {
-        ((ListProperty)prop).getOneTimeWriteAccess().setValue(
-            convertToPropertyType(value, prop.getType()),
-            coord
-        );
-        return;
-      }
-      ListPropertyWriteAccess prop_WA = ((ListProperty)prop).getWriteAccess(null);
-      // Clear the ListProperty
-      prop_WA.removeAll();
-      // Put all elements of aValue into the ListProperty
-      if ( value instanceof String ) {
-        // String vom Format "{ ... , ... , ... }", dann String
-        // splitten
-        String sepString = ((String) value).trim();
-        if ( sepString.startsWith("{") && sepString.endsWith("}") )
-          value = sepString.substring(1, sepString.length()-1).split(",");
-      }
-      if ( value instanceof Object[] )
-        for (Object arrayValue : (Object[])value)
-          prop_WA.addValue( convertToPropertyType(arrayValue, prop.getType()) );
-      else if ( value instanceof Iterable )
-        for (Object element : (Iterable)value)
-          prop_WA.addValue( convertToPropertyType(element, prop.getType()) );
-      prop_WA.release();
-    }
-    //*********** MatrixProperty **************
-    if (prop instanceof MatrixProperty) {
-      // if coordinates are given, the matrix element is set
-      if (coord.length > 0) {
-        ((MatrixProperty)prop).getOneTimeWriteAccess().setValue(
-            convertToPropertyType(value, prop.getType()),
-            coord
-        );
-        return;
-      }
-
-      MatrixProperty      matrixProp = (MatrixProperty)prop;
-      PropertyWriteAccess prop_WA    = (matrixProp).getWriteAccess(null);
-      int[]               dimSizes   = LangUtil.getArrayLength(value); // Size of the dimensions
-      if ( dimSizes.length != matrixProp.getDimension() )
-        throw new UnsupportedOperationException("Dimension of MatrixProperty differs from specified array: "+matrixProp.getDimension()+" <> "+dimSizes.length);
-
-      // Calculate the total number of elements in the matrix
-      int elemCount = 1;
-      for ( int dimSize : dimSizes )
-        elemCount *= dimSize;
-
-      // put the array elements in the MatrixProperty
-      coord = new int[ dimSizes.length ];
-      for ( int i=0; i<elemCount; i++ ) {
-        // set the MatrixProperty at coordinate tCoord
-        prop_WA.setValue(
-          convertToPropertyType(LangUtil.getArrayValue( value, coord ), prop.getType()),
-          coord
-        );
-
-        // increment the coordinate for the element
-        for (int d = 1; d < dimSizes.length; d++)
-          if (++coord[d] < dimSizes[d])
-            break; // Coordinates in dimensionen > d not influenced by the increment
-          else
-            coord[d] = 0; // Initialize coordinate in dimension d and continue
-                          // to increment in dimension d+1 erhoehen
-      }
-      prop_WA.release();
-    }
-  }
-
-  private static Object convertToPropertyType(Object value, Class neededType) {
-    // try to set the object directly to the property
-    if ( !neededType.isInstance(value) ) {
-      if ( value instanceof String )
-        value = BaseTypeUtil.convertFromString((String)value, neededType);
-    }
-    return value;
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data.property;
+
+import java.util.Vector;
+
+import schmitzm.lang.LangUtil;
+import schmitzm.temp.BaseTypeUtil;
+
+/**
+ * Diese Klasse beinhaltet statische Hilfsmethoden fuer das Arbeiten mit
+ * {@link Property} und {@link Properties}.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class PropertyUtil {
+
+  /**
+   * Liefert eine Eigenschaft eines {@link Properties}-Objekt.
+   * Enthaelt das {@link Properties}-Objekt keine Eigenschaft mit dem
+   * angegebenen Namen, wird dieser sukzessive verkuerzt (Punkt-Notation)
+   * bis im Objekt eine entsprechende Eigenschaft gefunden wird.
+   * In diesem Fall muss es sich beim Wert dieser Eigenschaft
+   * wiederum um ein {@link Properties}-Objekt handeln, um den "abgeschnittenen"
+   * Teil des Eigenschaft-Names rekursiv zu verarbeiten.
+   * @param propObject {@link Properties}-Objekt
+   * @param propSuffix Name der Eigenschaft (bzw. mehrere Eigenschaften
+   *                   durch "." getrennt)
+   * @return {@code null} wenn die Eigenschaft nicht gefunden werden kann
+   */
+  public static Property getProperty(Properties propObject, String propSuffix) {
+    return getProperty(propObject, propSuffix, '.');
+  }
+
+  /**
+   * Liefert den Wert eine Eigenschaft. Enthaelt das {@link Properties}-Objekt
+   * keine Eigenschaft mit dem angegebenen Namen, wird dieser sukzessive
+   * verkuerzt (Punkt-Notation) bis im Objekt eine entsprechende Eigenschaft
+   * gefunden wird. In diesem Fall muss es sich beim Wert dieser Eigenschaft
+   * wiederum um ein {@link Properties}-Objekt handeln, um den "abgeschnittenen"
+   * Teil des Eigenschaft-Names rekursiv zu verarbeiten.
+   * @param propObject {@link Properties}-Objekt
+   * @param propSuffix Name der Eigenschaft (bzw. mehrere Eigenschaften
+   *                   getrennt durch das {@code sep}-Zeichen)
+   * @param sep        Trenn-Zeichen, mit dem in {@link propSuffix} mehere Eigenschaften
+   *                   von einander getrennt sind
+   * @return {@code null} wenn die Eigenschaft nicht gefunden werden kann
+   */
+  public static Property getProperty(Properties propObject, String propSuffix, char sep) {
+    if ( propSuffix == null )
+      propSuffix = "";
+
+    String propName = propSuffix;
+    int[]  arrayCoord = new int[0];
+    propSuffix = "";
+    while ( !propName.equals("") ) {
+      Property prop = propObject.getProperty(propName);
+      if ( prop == null ) {
+        arrayCoord = getArrayCoordinates(propName);
+        if ( arrayCoord.length > 0 ) {
+          // cut the array coordinates
+          propName = cutArrayCoordinates(propName);
+          prop     = propObject.getProperty(propName);
+        }
+      }
+      // Property found
+      if ( prop != null ) {
+        // no more property names exist >> the object is the requested property (Juhuuuu!)
+        if ( propSuffix.equals("") )
+          return prop;
+
+        // more property names exist >> property must be a ScalarProperty containing
+        //                              a Properties to perform the property suffix
+        if ( prop instanceof ValueProperty ) {
+          Object propValue = ((ValueProperty)prop).getOneTimeReadAccess().getValue(arrayCoord);
+          if ( propValue instanceof Properties )
+            return getProperty((Properties)propValue, propSuffix, sep);
+        }
+      }
+
+      // cut at last "." and try the prefix as property name
+      int tLastDotIdx = propName.lastIndexOf(sep);
+      if ( !propSuffix.equals("") )
+        propSuffix += sep;
+      propSuffix += propName.substring(tLastDotIdx+1);
+      propName   =  tLastDotIdx > 0 ? propName.substring(0,tLastDotIdx) : "";
+    }
+    // Property not found in object
+    return null;
+  }
+
+  /**
+   * Ermittelt die am Ende eines Strings in runden Klammern spezifierten
+   * Koordinaten.
+   * @param objectSpec ein String
+   * @return int[0], wenn der String keine Klammerung am Ende enthaelt.
+   */
+  public static int[] getArrayCoordinates(String objectSpec) {
+    objectSpec = objectSpec.trim();
+    int[] arrayCoord = new int[0];
+    if ( objectSpec.endsWith(")") && objectSpec.contains("(")) {
+      int openIdx = objectSpec.lastIndexOf("(");
+      String[] arrayCoordStr = objectSpec.substring(openIdx+1,objectSpec.length()-1).split(",");
+      arrayCoord = new int[arrayCoordStr.length];
+      for (int i=0; i<arrayCoord.length; i++)
+        arrayCoord[i] = Integer.parseInt(arrayCoordStr[i].trim());
+    }
+    return arrayCoord;
+  }
+
+  /**
+   * Entfernt eine etwaige Koordinaten-Definition (in runden Klammern) am
+   * Ende eines Strings.
+   * @param objectSpec ein String
+   * @return den original String, wenn dieser keine Koordinaten-Definition
+   *         enthaelt
+   */
+  public static String cutArrayCoordinates(String objectSpec) {
+    if ( objectSpec.endsWith(")") && objectSpec.contains("("))
+      return objectSpec.substring(0, objectSpec.lastIndexOf("("));
+    return objectSpec;
+  }
+
+
+  /**
+   * Wraps a {@link Property} to an appropriate java object.
+   * <ul>
+   *   <li>{@link ScalarProperty}: wrapped to its (single) value</li>
+   *   <li>{@link ListProperty}: wrapped to an appropriate {@link Vector} which
+   *                             contains the {@link ListProperty} values</li>
+   *   <li>{@link MatrixProperty}: wrapped to an appropriate native {@code Object[]..[]}
+   *                               which contains the {@link MatrixProperty} values</li>
+   * </ul>
+   * @param prop   a property
+   * @param coord  <b>if specified, the appropiate element of the {@link ListProperty}
+   *               or {@link MatrixProperty} is returned, instead of the complete
+   *               list or matrix!</b>
+   * @return the Property itself, if no wrap can be performed
+   */
+  public static Object getPropertyValue(Property prop, int... coord) {
+    if ( coord == null )
+      coord = new int[0];
+
+    //*********** ScalarProperty **************
+    if ( prop instanceof ScalarProperty ) {
+      return ((ScalarProperty)prop).getOneTimeReadAccess().getValue();
+    }
+
+    //*********** ListProperty **************
+    if ( prop instanceof ListProperty ) {
+      // if coordinates are given, the list element is returned
+      if (coord.length > 0)
+        return ((ListProperty)prop).getOneTimeReadAccess().getValue(coord);
+      // return all list elements as Vector
+      ListPropertyReadAccess prop_RA = ((ListProperty)prop).getReadAccess(null);
+      Vector vector = new Vector( prop_RA.getCount() );
+      for (int i=0; i<prop_RA.getCount(); i++)
+        vector.add( prop_RA.getValue(i) );
+      prop_RA.release();
+      return vector;
+    }
+
+    //*********** MatrixProperty **************
+    if ( prop instanceof MatrixProperty ) {
+      // if coordinates are given, the matrix element is returned
+      if (coord.length > 0)
+        return ((MatrixProperty)prop).getOneTimeReadAccess().getValue(coord);
+
+      // challenge: MatrixProperty is generic and its dimension and
+      //            data type is not fixed
+      //            --> the creation of the target native array
+      //                must be realised generic too
+      MatrixProperty     matrixProp = (MatrixProperty)prop;
+      PropertyReadAccess prop_RA    = (matrixProp).getReadAccess(null);
+      int[]              dimSizes   = matrixProp.getSize(); // Size of the dimensions
+      Object             array      = LangUtil.createArray( dimSizes );
+      // Calculate the total number of elements in the matrix
+      int elemCount = 1;
+      for ( int dimSize : dimSizes )
+        elemCount *= dimSize;
+
+      // put the elements in the array
+      coord = new int[ dimSizes.length ];
+      for ( int i=0; i<elemCount; i++ ) {
+        // set the element at coordinate tCoord
+        LangUtil.setArrayValue(
+            array,
+            prop_RA.getValue( coord ),
+            coord
+        );
+
+        // increment the coordinate for the element
+        for (int d = 1; d < dimSizes.length; d++)
+          if (++coord[d] < dimSizes[d])
+            break; // Coordinates in dimensionen > d not influenced by the increment
+          else
+            coord[d] = 0; // Initialize coordinate in dimension d and continue
+                          // to increment in dimension d+1 erhoehen
+      }
+      prop_RA.release();
+      return array;
+    }
+
+    return prop;
+  }
+
+  /**
+   * Sets the value of a {@link Property} with an appropriate java object.
+   * <ul>
+   *   <li>{@link ScalarProperty}: sets the property's (single) value to {@code aValue}</li>
+   *   <li>{@link ListProperty}: clears the list and fills it with the
+   *                             elements of {@code aValue} (must be an {@code Object[]}
+   *                             or an {@link Iterable})</li>
+   *   <li>{@link MatrixProperty}: fills the matrix with the elements of
+   *                               {@code aValue} (must be an {@code Object[]})</li>
+   * </ul>
+   * @param prop   a property
+   * @param value  a value the property is set to
+   * @param coord  <b>if specified, only the appropiate element of the {@link ListProperty}
+   *               or {@link MatrixProperty} is set with {@code aValue},
+   *               instead of the complete list or matrix!</b>
+   */
+  public static void setPropertyValue(ValueProperty prop, Object value, int... coord) {
+    if ( coord == null )
+      coord = new int[0];
+
+    //*********** ScalarProperty **************
+    if (prop instanceof ScalarProperty)
+      ((ScalarProperty)prop).getOneTimeWriteAccess().setValue(
+          convertToPropertyType(value, prop.getType())
+      );
+
+    //*********** ListProperty **************
+    if (prop instanceof ListProperty) {
+      // if coordinates are given, the matrix element is set
+      if (coord.length > 0) {
+        ((ListProperty)prop).getOneTimeWriteAccess().setValue(
+            convertToPropertyType(value, prop.getType()),
+            coord
+        );
+        return;
+      }
+      ListPropertyWriteAccess prop_WA = ((ListProperty)prop).getWriteAccess(null);
+      // Clear the ListProperty
+      prop_WA.removeAll();
+      // Put all elements of aValue into the ListProperty
+      if ( value instanceof String ) {
+        // String vom Format "{ ... , ... , ... }", dann String
+        // splitten
+        String sepString = ((String) value).trim();
+        if ( sepString.startsWith("{") && sepString.endsWith("}") )
+          value = sepString.substring(1, sepString.length()-1).split(",");
+      }
+      if ( value instanceof Object[] )
+        for (Object arrayValue : (Object[])value)
+          prop_WA.addValue( convertToPropertyType(arrayValue, prop.getType()) );
+      else if ( value instanceof Iterable )
+        for (Object element : (Iterable)value)
+          prop_WA.addValue( convertToPropertyType(element, prop.getType()) );
+      prop_WA.release();
+    }
+    //*********** MatrixProperty **************
+    if (prop instanceof MatrixProperty) {
+      // if coordinates are given, the matrix element is set
+      if (coord.length > 0) {
+        ((MatrixProperty)prop).getOneTimeWriteAccess().setValue(
+            convertToPropertyType(value, prop.getType()),
+            coord
+        );
+        return;
+      }
+
+      MatrixProperty      matrixProp = (MatrixProperty)prop;
+      PropertyWriteAccess prop_WA    = (matrixProp).getWriteAccess(null);
+      int[]               dimSizes   = LangUtil.getArrayLength(value); // Size of the dimensions
+      if ( dimSizes.length != matrixProp.getDimension() )
+        throw new UnsupportedOperationException("Dimension of MatrixProperty differs from specified array: "+matrixProp.getDimension()+" <> "+dimSizes.length);
+
+      // Calculate the total number of elements in the matrix
+      int elemCount = 1;
+      for ( int dimSize : dimSizes )
+        elemCount *= dimSize;
+
+      // put the array elements in the MatrixProperty
+      coord = new int[ dimSizes.length ];
+      for ( int i=0; i<elemCount; i++ ) {
+        // set the MatrixProperty at coordinate tCoord
+        prop_WA.setValue(
+          convertToPropertyType(LangUtil.getArrayValue( value, coord ), prop.getType()),
+          coord
+        );
+
+        // increment the coordinate for the element
+        for (int d = 1; d < dimSizes.length; d++)
+          if (++coord[d] < dimSizes[d])
+            break; // Coordinates in dimensionen > d not influenced by the increment
+          else
+            coord[d] = 0; // Initialize coordinate in dimension d and continue
+                          // to increment in dimension d+1 erhoehen
+      }
+      prop_WA.release();
+    }
+  }
+
+  private static Object convertToPropertyType(Object value, Class neededType) {
+    // try to set the object directly to the property
+    if ( !neededType.isInstance(value) ) {
+      if ( value instanceof String )
+        value = BaseTypeUtil.convertFromString((String)value, neededType);
+    }
+    return value;
+  }
+
+}

Modified: trunk/src/schmitzm/data/property/PropertyWriteAccess.java
===================================================================
--- trunk/src/schmitzm/data/property/PropertyWriteAccess.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/property/PropertyWriteAccess.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,81 +1,99 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data.property;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+/**
+ * Diese Klasse stellt ein Recht auf Schreibzugriff fuer eine
+ * {@link ValueProperty} dar.
+ * Hierzu implementiert sie die entsprechenden <code>setter</code>-Methoden.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class PropertyWriteAccess extends PropertyReadAccess {
+  private ValueProperty property = null;
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+  /**
+   * Erzeugt ein neues Schreibzugriffsrecht. Die Anzahl an Zugriffen fuer den
+   * Besitzer ist unbegrenzt.
+   * @param object Instanz von <code>ValueProperty</code> auf die sich das Recht bezieht
+   * @param owner  Besitzer des Rechts
+   * @see schmitzm.data.property.ValueProperty
+   * @exception schmitzm.data.property.AccessViolationException falls das
+   *            angegebene Objekt <b>keine</b> <code>ValueProperty</code> ist
+   */
+  public PropertyWriteAccess(Accessible object, Object owner) {
+    this(object,owner,UNLIMITED_ACCESSTIMES);
+  }
 
-package schmitzm.data.property;
-
-/**
- * Diese Klasse stellt ein Recht auf Schreibzugriff fuer eine
- * {@link ValueProperty} dar.
- * Hierzu implementiert sie die entsprechenden <code>setter</code>-Methoden.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class PropertyWriteAccess extends PropertyReadAccess {
-  private ValueProperty property = null;
-
-  /**
-   * Erzeugt ein neues Schreibzugriffsrecht. Die Anzahl an Zugriffen fuer den
-   * Besitzer ist unbegrenzt.
-   * @param object Instanz von <code>ValueProperty</code> auf die sich das Recht bezieht
-   * @param owner  Besitzer des Rechts
-   * @see schmitzm.data.property.ValueProperty
-   * @exception schmitzm.data.property.AccessViolationException falls das
-   *            angegebene Objekt <b>keine</b> <code>ValueProperty</code> ist
-   */
-  public PropertyWriteAccess(Accessible object, Object owner) {
-    this(object,owner,UNLIMITED_ACCESSTIMES);
-  }
-
-  /**
-   * Erzeugt ein neues Schreibzugriffsrecht.
-   * @param object Instanz von <code>ValueProperty</code> auf die sich das Recht bezieht
-   * @param owner  Besitzer des Rechts
-   * @param maxAccessTimes Anzahl an (Methoden-)Zugriffen, die der Rechtebesitzer
-   *                       taetigen darf, bevor das Recht automatisch entzogen wird
-   * @see schmitzm.data.property.ValueProperty
-   * @exception schmitzm.data.property.AccessViolationException falls das
-   *            angegebene Objekt <b>keine</b> <code>ValueProperty</code> ist
-   */
-  public PropertyWriteAccess(Accessible object, Object owner, int maxAccessTimes) {
-    super(object,owner,maxAccessTimes);
-    if (!(object instanceof ValueProperty))
-      throw new AccessViolationException(this,this.getClass().getName()+" can only be instantiated for ValueProperties");
-    property = (ValueProperty)object;
-  }
-
-  /**
-   * Setzt den/einen Wert der Eigenschaft.<br>
-   * <code>coords</code> spezifizieren (optional) die "Koordinaten", an denen
-   * der Wert in der Eigenschaft zu finden ist.
-   * Fuer skalare Eigenschaften darf/braucht diese Angabe nicht gemacht zu
-   * werden. Fuer Listen und 1-dim. Matrizen (Arrays) darf nur ein Wert
-   * angegeben werden. Fuer mehr-dimensionale Matrizen muessen entsprechend
-   * der Dimension mehr Koordinaten angegeben werden (als einzelne Parameter oder
-   * als ein Array). z.B. fuer 2-dim. Matrix:<br>
-   * <code>getValue(10,13)</code> oder <code>getValue( new int[] {10,13} )</code><br>
-   * <br>
-   * Kann (seit JDK1.5.0) auch genutzt werden, wenn es sich bei der Property um einen
-   * Build-in-Type handelt.
-   * Iniziiert ein <code>ObjectChangeEvent</code> fuer die Property.
-   * @param value  neuer Wert fuer die Eigenschaft
-   * @param coords optionale Koordinaten
-   * @exception java.lang.ClassCastException falls das angegebene Objekt nicht
-   *            zum Property-Typ passt
-   * @exception schmitzm.data.property.AccessViolationException falls
-   *            das Schreibrecht auf der Property nicht mehr gueltig ist
-   */
-  public void setValue(Object value, int... coords) {
-    checkDisposed();
-    this.property.setValue(value,coords);
-    incAndCheckMaxAccessTimesReached();
-  }
-
-}
+  /**
+   * Erzeugt ein neues Schreibzugriffsrecht.
+   * @param object Instanz von <code>ValueProperty</code> auf die sich das Recht bezieht
+   * @param owner  Besitzer des Rechts
+   * @param maxAccessTimes Anzahl an (Methoden-)Zugriffen, die der Rechtebesitzer
+   *                       taetigen darf, bevor das Recht automatisch entzogen wird
+   * @see schmitzm.data.property.ValueProperty
+   * @exception schmitzm.data.property.AccessViolationException falls das
+   *            angegebene Objekt <b>keine</b> <code>ValueProperty</code> ist
+   */
+  public PropertyWriteAccess(Accessible object, Object owner, int maxAccessTimes) {
+    super(object,owner,maxAccessTimes);
+    if (!(object instanceof ValueProperty))
+      throw new AccessViolationException(this,this.getClass().getName()+" can only be instantiated for ValueProperties");
+    property = (ValueProperty)object;
+  }
+
+  /**
+   * Setzt den/einen Wert der Eigenschaft.<br>
+   * <code>coords</code> spezifizieren (optional) die "Koordinaten", an denen
+   * der Wert in der Eigenschaft zu finden ist.
+   * Fuer skalare Eigenschaften darf/braucht diese Angabe nicht gemacht zu
+   * werden. Fuer Listen und 1-dim. Matrizen (Arrays) darf nur ein Wert
+   * angegeben werden. Fuer mehr-dimensionale Matrizen muessen entsprechend
+   * der Dimension mehr Koordinaten angegeben werden (als einzelne Parameter oder
+   * als ein Array). z.B. fuer 2-dim. Matrix:<br>
+   * <code>getValue(10,13)</code> oder <code>getValue( new int[] {10,13} )</code><br>
+   * <br>
+   * Kann (seit JDK1.5.0) auch genutzt werden, wenn es sich bei der Property um einen
+   * Build-in-Type handelt.
+   * Iniziiert ein <code>ObjectChangeEvent</code> fuer die Property.
+   * @param value  neuer Wert fuer die Eigenschaft
+   * @param coords optionale Koordinaten
+   * @exception java.lang.ClassCastException falls das angegebene Objekt nicht
+   *            zum Property-Typ passt
+   * @exception schmitzm.data.property.AccessViolationException falls
+   *            das Schreibrecht auf der Property nicht mehr gueltig ist
+   */
+  public void setValue(Object value, int... coords) {
+    checkDisposed();
+    this.property.setValue(value,coords);
+    incAndCheckMaxAccessTimesReached();
+  }
+
+}

Modified: trunk/src/schmitzm/data/property/ScalarProperty.java
===================================================================
--- trunk/src/schmitzm/data/property/ScalarProperty.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/property/ScalarProperty.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,14 +1,32 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package schmitzm.data.property;
 
 import schmitzm.data.event.Invoker;

Modified: trunk/src/schmitzm/data/property/ValueProperty.java
===================================================================
--- trunk/src/schmitzm/data/property/ValueProperty.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/property/ValueProperty.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,14 +1,32 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package schmitzm.data.property;
 
 import java.util.Enumeration;

Modified: trunk/src/schmitzm/data/property/ValuePropertyAccessParameters.java
===================================================================
--- trunk/src/schmitzm/data/property/ValuePropertyAccessParameters.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/property/ValuePropertyAccessParameters.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,74 +1,92 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data.property;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+/**
+ * Diese Klasse stellt Rechte-Parameter fuer Wert-Eigenschaften (<code>ValueProperty</code>)
+ * dar. Fuer eine Wert-Eigenschaft koennen Lese- und Schreibrechte vergeben
+ * werden. Ueber die Parameter dieser Klasse kann festgelegt werden, wie
+ * viele Objekte gleichzeitig das jeweilige Recht besitzenm duerfen.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class ValuePropertyAccessParameters {
+  /** Konstante, die fuer unbegrenzten (Lese- oder Schreib-)Zugriff steht. */
+  public static final int UNLIMITED = -1;
+  /** Vordefinierte Parameter fuer unbegrenzten Lese- und unbegrenzten Schreibzugriff. */
+  public static final ValuePropertyAccessParameters UNLIMITED_ACCESS = new ValuePropertyAccessParameters(UNLIMITED,UNLIMITED);
+  /** Vordefinierte Parameter fuer unbegrenzten Lese- und isolierten Schreibzugriff
+   * (max. ein Schreibzugriffsrecht zu jedem Zeitpunkt). */
+  public static final ValuePropertyAccessParameters DEFAULT_ACCESS   = new ValuePropertyAccessParameters(UNLIMITED,1);
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+  private int simRead = 0;
+  private int simWrite = 0;
 
-package schmitzm.data.property;
-
-/**
- * Diese Klasse stellt Rechte-Parameter fuer Wert-Eigenschaften (<code>ValueProperty</code>)
- * dar. Fuer eine Wert-Eigenschaft koennen Lese- und Schreibrechte vergeben
- * werden. Ueber die Parameter dieser Klasse kann festgelegt werden, wie
- * viele Objekte gleichzeitig das jeweilige Recht besitzenm duerfen.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class ValuePropertyAccessParameters {
-  /** Konstante, die fuer unbegrenzten (Lese- oder Schreib-)Zugriff steht. */
-  public static final int UNLIMITED = -1;
-  /** Vordefinierte Parameter fuer unbegrenzten Lese- und unbegrenzten Schreibzugriff. */
-  public static final ValuePropertyAccessParameters UNLIMITED_ACCESS = new ValuePropertyAccessParameters(UNLIMITED,UNLIMITED);
-  /** Vordefinierte Parameter fuer unbegrenzten Lese- und isolierten Schreibzugriff
-   * (max. ein Schreibzugriffsrecht zu jedem Zeitpunkt). */
-  public static final ValuePropertyAccessParameters DEFAULT_ACCESS   = new ValuePropertyAccessParameters(UNLIMITED,1);
-
-  private int simRead = 0;
-  private int simWrite = 0;
-
-  /**
-   * Erzeugt neue Parameter fuer Wert-Eigenschaften.
-   * @param simultanRead Anzahl an Objekten, die glz. lesen duerfen
-   * @param simultanWrite Anzahl an Objekten, die glz. schreiben duerfen
-   */
-  public ValuePropertyAccessParameters(int simultanRead, int simultanWrite) {
-    this.simRead = simultanRead;
-    this.simWrite = simultanWrite;
-  }
-
-  /**
-   * Liefert die Anzahl an Objekten die gleichzeitig lesen duerfen.
-   * @return <code>UNLIMITED</code> falls beliebig viele Objekte glz. lesen duerfen
-   */
-  public int getSimultanReadAccess() {
-    return this.simRead;
-  }
-
-  /**
-   * Prueft, ob beliebig viele Objekte gleichzeitig lesen duerfen.
-   */
-  public boolean isReadUnlimited() {
-    return getSimultanReadAccess()==UNLIMITED;
-  }
-
-  /**
-   * Liefert die Anzahl an Objekten die gleichzeitig schreiben duerfen.
-   * @return <code>UNLIMITED</code> falls beliebig viele Objekte glz. schreiben duerfen
-   */
-  public int getSimultanWriteAccess() {
-    return this.simWrite;
-  }
-
-  /**
-   * Prueft, ob beliebig viele Objekte gleichzeitig schreiben duerfen.
-   */
-  public boolean isWriteUnlimited() {
-    return getSimultanWriteAccess()==UNLIMITED;
-  }
-
-}
+  /**
+   * Erzeugt neue Parameter fuer Wert-Eigenschaften.
+   * @param simultanRead Anzahl an Objekten, die glz. lesen duerfen
+   * @param simultanWrite Anzahl an Objekten, die glz. schreiben duerfen
+   */
+  public ValuePropertyAccessParameters(int simultanRead, int simultanWrite) {
+    this.simRead = simultanRead;
+    this.simWrite = simultanWrite;
+  }
+
+  /**
+   * Liefert die Anzahl an Objekten die gleichzeitig lesen duerfen.
+   * @return <code>UNLIMITED</code> falls beliebig viele Objekte glz. lesen duerfen
+   */
+  public int getSimultanReadAccess() {
+    return this.simRead;
+  }
+
+  /**
+   * Prueft, ob beliebig viele Objekte gleichzeitig lesen duerfen.
+   */
+  public boolean isReadUnlimited() {
+    return getSimultanReadAccess()==UNLIMITED;
+  }
+
+  /**
+   * Liefert die Anzahl an Objekten die gleichzeitig schreiben duerfen.
+   * @return <code>UNLIMITED</code> falls beliebig viele Objekte glz. schreiben duerfen
+   */
+  public int getSimultanWriteAccess() {
+    return this.simWrite;
+  }
+
+  /**
+   * Prueft, ob beliebig viele Objekte gleichzeitig schreiben duerfen.
+   */
+  public boolean isWriteUnlimited() {
+    return getSimultanWriteAccess()==UNLIMITED;
+  }
+
+}

Modified: trunk/src/schmitzm/data/property/ValuePropertyType.java
===================================================================
--- trunk/src/schmitzm/data/property/ValuePropertyType.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/property/ValuePropertyType.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,240 +1,258 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.data.property;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.data.property;
-
 import schmitzm.data.ObjectStructure;
 import schmitzm.data.ObjectStructureUtil;
 import schmitzm.temp.BaseTypeUtil;
-
-/**
- * Diese Klasse repraesentiert den Datentyp einer {@linkplain ValueProperty Wert-Eigenschaft}.
- * Der Datentyp kann aus einer einfachen Klasse bestehen, oder aus oder aus
- * einer komplexen  {@linkplain ObjectStructure Objekt-Struktur}.
- * <b>Bemerke:</b><br>
- * Fuer Basis-Datentypen (<code>int</code>, <code>double</code>,
- * <code>String</code>, ...) sollten keine neuen
- * <code>ValuePropertyType</code>-Instanzen erzeugt werden, sondern die
- * bereits implementierten Konstanten verwendet werden!
- * @see #TYPE_BYTE
- * @see #TYPE_SHORT
- * @see #TYPE_INT
- * @see #TYPE_LONG
- * @see #TYPE_FLOAT
- * @see #TYPE_DOUBLE
- * @see #TYPE_BOOLEAN
- * @see #TYPE_CHAR
- * @see #TYPE_STRING
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class ValuePropertyType extends PropertyType {
-  /**
-   * Speichert die Struktur der Objekte, die fuer den Property-Wert zulaessig
-   * ist.
-   */
-  protected ObjectStructure structure = null;
-
-  /** Repraesentiert eine vorgefertigte {@link Byte}-Eigenschaft. **/
-  public static final ValuePropertyType TYPE_BYTE    = new ValuePropertyType(Byte.class);
-  /** Repraesentiert eine vorgefertigte {@link Short}-Eigenschaft. **/
-  public static final ValuePropertyType TYPE_SHORT   = new ValuePropertyType(Short.class);
-  /** Repraesentiert eine vorgefertigte {@link Integer}-Eigenschaft. **/
-  public static final ValuePropertyType TYPE_INT     = new ValuePropertyType(Integer.class);
-  /** Repraesentiert eine vorgefertigte {@link Long}-Eigenschaft. **/
-  public static final ValuePropertyType TYPE_LONG    = new ValuePropertyType(Long.class);
-  /** Repraesentiert eine vorgefertigte {@link Float}-Eigenschaft. **/
-  public static final ValuePropertyType TYPE_FLOAT   = new ValuePropertyType(Float.class);
-  /** Repraesentiert eine vorgefertigte {@link Double}-Eigenschaft. **/
-  public static final ValuePropertyType TYPE_DOUBLE  = new ValuePropertyType(Double.class);
-  /** Repraesentiert eine vorgefertigte {@link Boolean}-Eigenschaft. **/
-  public static final ValuePropertyType TYPE_BOOLEAN = new ValuePropertyType(Boolean.class);
-  /** Repraesentiert eine vorgefertigte {@link Character}-Eigenschaft. **/
-  public static final ValuePropertyType TYPE_CHAR    = new ValuePropertyType(Character.class);
-  /** Repraesentiert eine vorgefertigte {@link String}-Eigenschaft. **/
-  public static final ValuePropertyType TYPE_STRING  = new ValuePropertyType(String.class);
-
-  /**
-   * Liefert einen passenden Property-Typ zu einem Datentyp oder einem
-   * Beispiel-Objekt. Handelt es sich um
-   * einen Basis-Datentyp (<code>Integer</code>, <code>Double</code>,
-   * <code>String</code>, ...) wird eine der konstanten
-   * <code>ValuePropertyType</code>-Instanzen zurueckgegeben. Andernfalls wird
-   * versucht den Beispielwert ueber den Standard-Konstruktor der angegebenen
-   * Klasse zu erzeugen. Schlaegt dies fehl, wird der Beispiel-Wert auf
-   * <code>null</code> gesetzt.
-   * @param sample Typ den die Eigenschaft aufnehmen soll (<code>Class</code>,
-   *               <code>ObjectStructure</code> oder Beispiel-<code>Object</code>)
-   * @see #TYPE_BYTE
-   * @see #TYPE_SHORT
-   * @see #TYPE_INT
-   * @see #TYPE_LONG
-   * @see #TYPE_FLOAT
-   * @see #TYPE_DOUBLE
-   * @see #TYPE_BOOLEAN
-   * @see #TYPE_CHAR
-   * @see #TYPE_STRING
-   */
-  public static ValuePropertyType createValuePropertyType(Object sample) {
-    if ( sample == null )
-      throw new UnsupportedOperationException("Can not create a PropertyType from null");
-
-    // Wenn es sich um eine Structure handelt, diese verwenden
-    if ( sample instanceof ObjectStructure )
-      return new ValuePropertyType( (ObjectStructure)sample );
-
-    // Fuer Basis-Datentypen die Konstanten verwenden
-    // Bemerke: Leider werden fuer Class-Objekte nicht die BaseTypeUtil-Methoden
-    //          fuer Class aufgerufen, sondern fuer Object!! (warum?)
-    //          Deshalb muss hier leider fallunterschieden und explizit
-    //          gecastet werden
-    if ( sample instanceof Class ) {
-      if (BaseTypeUtil.isByte((Class)sample))
-        return TYPE_BYTE;
-      if (BaseTypeUtil.isShort((Class)sample))
-        return TYPE_SHORT;
-      if (BaseTypeUtil.isInteger((Class)sample))
-        return TYPE_INT;
-      if (BaseTypeUtil.isLong((Class)sample))
-        return TYPE_LONG;
-      if (BaseTypeUtil.isFloat((Class)sample))
-        return TYPE_FLOAT;
-      if (BaseTypeUtil.isDouble((Class)sample))
-        return TYPE_DOUBLE;
-      if (BaseTypeUtil.isBoolean((Class)sample))
-        return TYPE_BOOLEAN;
-      if (BaseTypeUtil.isCharacter((Class)sample))
-        return TYPE_CHAR;
-      if (BaseTypeUtil.isString((Class)sample))
-        return TYPE_STRING;
-      // sonst Property-Typ neu erzeugen
-      return new ValuePropertyType((Class)sample);
-    } else {
-      if (BaseTypeUtil.isByte(sample))
-        return TYPE_BYTE;
-      if (BaseTypeUtil.isShort(sample))
-        return TYPE_SHORT;
-      if (BaseTypeUtil.isInteger(sample))
-        return TYPE_INT;
-      if (BaseTypeUtil.isLong(sample))
-        return TYPE_LONG;
-      if (BaseTypeUtil.isFloat(sample))
-        return TYPE_FLOAT;
-      if (BaseTypeUtil.isDouble(sample))
-        return TYPE_DOUBLE;
-      if (BaseTypeUtil.isBoolean(sample))
-        return TYPE_BOOLEAN;
-      if (BaseTypeUtil.isCharacter(sample))
-        return TYPE_CHAR;
-      if (BaseTypeUtil.isString(sample))
-        return TYPE_STRING;
-      // sonst Property-Typ neu erzeugen
-      return new ValuePropertyType(sample.getClass());
-    }
-  }
-
-  /**
-   * Erzeugt einen neuen Eigenschaftstyp.
-   * <b>Bemerke:</b><br>
-   * Fuer Basis-Datentypen (<code>Integer</code>, <code>Double</code>,
-   * <code>String</code>, ...) sollte nicht dieser Konstruktor verwendet werden,
-   * sondern eine der konstanten <code>ValuePropertyType</code>-Instanzen.
-   * @param sample Beispielwert
-   * @exception java.lang.UnsupportedOperationException falls der Beispiel-Wert
-   *            keine Instanz des Eigenschaftstyp ist.
-   * @see #TYPE_BYTE
-   * @see #TYPE_SHORT
-   * @see #TYPE_INT
-   * @see #TYPE_LONG
-   * @see #TYPE_FLOAT
-   * @see #TYPE_DOUBLE
-   * @see #TYPE_BOOLEAN
-   * @see #TYPE_CHAR
-   * @see #TYPE_STRING
-   */
-  public ValuePropertyType(ObjectStructure sample) {
-    super(sample.getClass());
-    this.structure = sample;
-  }
-
-  /**
-   * Erzeugt einen neuen Eigenschaftstyp. Der Beispielwert wird ueber den
-   * Standard-Konstruktor der Typ-Klasse zu instanziieren versucht. Schlaegt
-   * dies fehl, wird der Beispiel-Wert auf <code>null</code> gesetzt.<br>
-   * <b>Bemerke:</b><br>
-   * Fuer Basis-Datentypen (<code>Integer</code>, <code>Double</code>,
-   * <code>String</code>, ...) sollte nicht dieser Konstruktor verwendet werden,
-   * sondern eine der konstanten <code>ValuePropertyType</code>-Instanzen.
-   * @param type Typ den die Eigenschaft aufnehmen kann
-   * @see #TYPE_BYTE
-   * @see #TYPE_SHORT
-   * @see #TYPE_INT
-   * @see #TYPE_LONG
-   * @see #TYPE_FLOAT
-   * @see #TYPE_DOUBLE
-   * @see #TYPE_BOOLEAN
-   * @see #TYPE_CHAR
-   * @see #TYPE_STRING
-   */
-  public ValuePropertyType(Class type) {
-    super(type);
-    this.structure = null;
-  }
-
-  /**
-   * Prueft, ob der Eigenschaftstyp aus einer festen Struktur besteht.
-   * @return <code>false</code> falls der Eigenschaftstyp lediglich durch eine Klasse
-   *         festgelegt ist
-   */
-  public boolean isStructured() {
-    return getTypeStructure() != null;
-  }
-
-  /**
-   * Liefert die (feste) Struktur des Eigenschaftstyp.
-   * @return <code>null</code> falls der Eigenschaftstyp lediglich durch eine Klasse
-   *         festgelegt ist
-   */
-  public ObjectStructure getTypeStructure() {
-    return structure;
-  }
-
-  /**
-   * Prueft, ob der Datentyp mit einem anderen <b>strukturell</b> identisch ist.
-   * Der Inhalt der Eigenschaft wird nicht beachtet
-   * @param typeObj kann eine <code>ValuePropertyType</code>-Instanz sein, oder
-   *                auch eine {@link ValueProperty}-Instanz
-   */
-  public boolean equalsInStructure(Object typeObj) {
-    // ValuePropertyType-Instanz aus uebergebenen Objekt ermitteln
-    ValuePropertyType type = null;
-    if ( typeObj instanceof ValuePropertyType )
-      type = (ValuePropertyType)typeObj;
-    if ( typeObj instanceof ValueProperty )
-      type = ((ValueProperty)typeObj).getPropertyType();
-    // ein vergleichbarere Typ
-    if ( type == null )
-      return false;
-
-    // wenn beide strukturiert sind, die Struktur vergleichen
-    if ( isStructured() ) {
-      if ( !type.isStructured() )
-          return false;
-      return ObjectStructureUtil.compareObjectStructures(getTypeStructure(),type.getTypeStructure()) == ObjectStructureUtil.EQUAL;
-    } else {
-      // wenn beide nicht strukturiert sind, die Klassen vergleichen
-      if ( type.isStructured() )
-          return false;
-      return getType().equals( type.getType() );
-    }
-  }
-
- }
+
+/**
+ * Diese Klasse repraesentiert den Datentyp einer {@linkplain ValueProperty Wert-Eigenschaft}.
+ * Der Datentyp kann aus einer einfachen Klasse bestehen, oder aus oder aus
+ * einer komplexen  {@linkplain ObjectStructure Objekt-Struktur}.
+ * <b>Bemerke:</b><br>
+ * Fuer Basis-Datentypen (<code>int</code>, <code>double</code>,
+ * <code>String</code>, ...) sollten keine neuen
+ * <code>ValuePropertyType</code>-Instanzen erzeugt werden, sondern die
+ * bereits implementierten Konstanten verwendet werden!
+ * @see #TYPE_BYTE
+ * @see #TYPE_SHORT
+ * @see #TYPE_INT
+ * @see #TYPE_LONG
+ * @see #TYPE_FLOAT
+ * @see #TYPE_DOUBLE
+ * @see #TYPE_BOOLEAN
+ * @see #TYPE_CHAR
+ * @see #TYPE_STRING
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class ValuePropertyType extends PropertyType {
+  /**
+   * Speichert die Struktur der Objekte, die fuer den Property-Wert zulaessig
+   * ist.
+   */
+  protected ObjectStructure structure = null;
+
+  /** Repraesentiert eine vorgefertigte {@link Byte}-Eigenschaft. **/
+  public static final ValuePropertyType TYPE_BYTE    = new ValuePropertyType(Byte.class);
+  /** Repraesentiert eine vorgefertigte {@link Short}-Eigenschaft. **/
+  public static final ValuePropertyType TYPE_SHORT   = new ValuePropertyType(Short.class);
+  /** Repraesentiert eine vorgefertigte {@link Integer}-Eigenschaft. **/
+  public static final ValuePropertyType TYPE_INT     = new ValuePropertyType(Integer.class);
+  /** Repraesentiert eine vorgefertigte {@link Long}-Eigenschaft. **/
+  public static final ValuePropertyType TYPE_LONG    = new ValuePropertyType(Long.class);
+  /** Repraesentiert eine vorgefertigte {@link Float}-Eigenschaft. **/
+  public static final ValuePropertyType TYPE_FLOAT   = new ValuePropertyType(Float.class);
+  /** Repraesentiert eine vorgefertigte {@link Double}-Eigenschaft. **/
+  public static final ValuePropertyType TYPE_DOUBLE  = new ValuePropertyType(Double.class);
+  /** Repraesentiert eine vorgefertigte {@link Boolean}-Eigenschaft. **/
+  public static final ValuePropertyType TYPE_BOOLEAN = new ValuePropertyType(Boolean.class);
+  /** Repraesentiert eine vorgefertigte {@link Character}-Eigenschaft. **/
+  public static final ValuePropertyType TYPE_CHAR    = new ValuePropertyType(Character.class);
+  /** Repraesentiert eine vorgefertigte {@link String}-Eigenschaft. **/
+  public static final ValuePropertyType TYPE_STRING  = new ValuePropertyType(String.class);
+
+  /**
+   * Liefert einen passenden Property-Typ zu einem Datentyp oder einem
+   * Beispiel-Objekt. Handelt es sich um
+   * einen Basis-Datentyp (<code>Integer</code>, <code>Double</code>,
+   * <code>String</code>, ...) wird eine der konstanten
+   * <code>ValuePropertyType</code>-Instanzen zurueckgegeben. Andernfalls wird
+   * versucht den Beispielwert ueber den Standard-Konstruktor der angegebenen
+   * Klasse zu erzeugen. Schlaegt dies fehl, wird der Beispiel-Wert auf
+   * <code>null</code> gesetzt.
+   * @param sample Typ den die Eigenschaft aufnehmen soll (<code>Class</code>,
+   *               <code>ObjectStructure</code> oder Beispiel-<code>Object</code>)
+   * @see #TYPE_BYTE
+   * @see #TYPE_SHORT
+   * @see #TYPE_INT
+   * @see #TYPE_LONG
+   * @see #TYPE_FLOAT
+   * @see #TYPE_DOUBLE
+   * @see #TYPE_BOOLEAN
+   * @see #TYPE_CHAR
+   * @see #TYPE_STRING
+   */
+  public static ValuePropertyType createValuePropertyType(Object sample) {
+    if ( sample == null )
+      throw new UnsupportedOperationException("Can not create a PropertyType from null");
+
+    // Wenn es sich um eine Structure handelt, diese verwenden
+    if ( sample instanceof ObjectStructure )
+      return new ValuePropertyType( (ObjectStructure)sample );
+
+    // Fuer Basis-Datentypen die Konstanten verwenden
+    // Bemerke: Leider werden fuer Class-Objekte nicht die BaseTypeUtil-Methoden
+    //          fuer Class aufgerufen, sondern fuer Object!! (warum?)
+    //          Deshalb muss hier leider fallunterschieden und explizit
+    //          gecastet werden
+    if ( sample instanceof Class ) {
+      if (BaseTypeUtil.isByte((Class)sample))
+        return TYPE_BYTE;
+      if (BaseTypeUtil.isShort((Class)sample))
+        return TYPE_SHORT;
+      if (BaseTypeUtil.isInteger((Class)sample))
+        return TYPE_INT;
+      if (BaseTypeUtil.isLong((Class)sample))
+        return TYPE_LONG;
+      if (BaseTypeUtil.isFloat((Class)sample))
+        return TYPE_FLOAT;
+      if (BaseTypeUtil.isDouble((Class)sample))
+        return TYPE_DOUBLE;
+      if (BaseTypeUtil.isBoolean((Class)sample))
+        return TYPE_BOOLEAN;
+      if (BaseTypeUtil.isCharacter((Class)sample))
+        return TYPE_CHAR;
+      if (BaseTypeUtil.isString((Class)sample))
+        return TYPE_STRING;
+      // sonst Property-Typ neu erzeugen
+      return new ValuePropertyType((Class)sample);
+    } else {
+      if (BaseTypeUtil.isByte(sample))
+        return TYPE_BYTE;
+      if (BaseTypeUtil.isShort(sample))
+        return TYPE_SHORT;
+      if (BaseTypeUtil.isInteger(sample))
+        return TYPE_INT;
+      if (BaseTypeUtil.isLong(sample))
+        return TYPE_LONG;
+      if (BaseTypeUtil.isFloat(sample))
+        return TYPE_FLOAT;
+      if (BaseTypeUtil.isDouble(sample))
+        return TYPE_DOUBLE;
+      if (BaseTypeUtil.isBoolean(sample))
+        return TYPE_BOOLEAN;
+      if (BaseTypeUtil.isCharacter(sample))
+        return TYPE_CHAR;
+      if (BaseTypeUtil.isString(sample))
+        return TYPE_STRING;
+      // sonst Property-Typ neu erzeugen
+      return new ValuePropertyType(sample.getClass());
+    }
+  }
+
+  /**
+   * Erzeugt einen neuen Eigenschaftstyp.
+   * <b>Bemerke:</b><br>
+   * Fuer Basis-Datentypen (<code>Integer</code>, <code>Double</code>,
+   * <code>String</code>, ...) sollte nicht dieser Konstruktor verwendet werden,
+   * sondern eine der konstanten <code>ValuePropertyType</code>-Instanzen.
+   * @param sample Beispielwert
+   * @exception java.lang.UnsupportedOperationException falls der Beispiel-Wert
+   *            keine Instanz des Eigenschaftstyp ist.
+   * @see #TYPE_BYTE
+   * @see #TYPE_SHORT
+   * @see #TYPE_INT
+   * @see #TYPE_LONG
+   * @see #TYPE_FLOAT
+   * @see #TYPE_DOUBLE
+   * @see #TYPE_BOOLEAN
+   * @see #TYPE_CHAR
+   * @see #TYPE_STRING
+   */
+  public ValuePropertyType(ObjectStructure sample) {
+    super(sample.getClass());
+    this.structure = sample;
+  }
+
+  /**
+   * Erzeugt einen neuen Eigenschaftstyp. Der Beispielwert wird ueber den
+   * Standard-Konstruktor der Typ-Klasse zu instanziieren versucht. Schlaegt
+   * dies fehl, wird der Beispiel-Wert auf <code>null</code> gesetzt.<br>
+   * <b>Bemerke:</b><br>
+   * Fuer Basis-Datentypen (<code>Integer</code>, <code>Double</code>,
+   * <code>String</code>, ...) sollte nicht dieser Konstruktor verwendet werden,
+   * sondern eine der konstanten <code>ValuePropertyType</code>-Instanzen.
+   * @param type Typ den die Eigenschaft aufnehmen kann
+   * @see #TYPE_BYTE
+   * @see #TYPE_SHORT
+   * @see #TYPE_INT
+   * @see #TYPE_LONG
+   * @see #TYPE_FLOAT
+   * @see #TYPE_DOUBLE
+   * @see #TYPE_BOOLEAN
+   * @see #TYPE_CHAR
+   * @see #TYPE_STRING
+   */
+  public ValuePropertyType(Class type) {
+    super(type);
+    this.structure = null;
+  }
+
+  /**
+   * Prueft, ob der Eigenschaftstyp aus einer festen Struktur besteht.
+   * @return <code>false</code> falls der Eigenschaftstyp lediglich durch eine Klasse
+   *         festgelegt ist
+   */
+  public boolean isStructured() {
+    return getTypeStructure() != null;
+  }
+
+  /**
+   * Liefert die (feste) Struktur des Eigenschaftstyp.
+   * @return <code>null</code> falls der Eigenschaftstyp lediglich durch eine Klasse
+   *         festgelegt ist
+   */
+  public ObjectStructure getTypeStructure() {
+    return structure;
+  }
+
+  /**
+   * Prueft, ob der Datentyp mit einem anderen <b>strukturell</b> identisch ist.
+   * Der Inhalt der Eigenschaft wird nicht beachtet
+   * @param typeObj kann eine <code>ValuePropertyType</code>-Instanz sein, oder
+   *                auch eine {@link ValueProperty}-Instanz
+   */
+  public boolean equalsInStructure(Object typeObj) {
+    // ValuePropertyType-Instanz aus uebergebenen Objekt ermitteln
+    ValuePropertyType type = null;
+    if ( typeObj instanceof ValuePropertyType )
+      type = (ValuePropertyType)typeObj;
+    if ( typeObj instanceof ValueProperty )
+      type = ((ValueProperty)typeObj).getPropertyType();
+    // ein vergleichbarere Typ
+    if ( type == null )
+      return false;
+
+    // wenn beide strukturiert sind, die Struktur vergleichen
+    if ( isStructured() ) {
+      if ( !type.isStructured() )
+          return false;
+      return ObjectStructureUtil.compareObjectStructures(getTypeStructure(),type.getTypeStructure()) == ObjectStructureUtil.EQUAL;
+    } else {
+      // wenn beide nicht strukturiert sind, die Klassen vergleichen
+      if ( type.isStructured() )
+          return false;
+      return getType().equals( type.getType() );
+    }
+  }
+
+ }

Modified: trunk/src/schmitzm/data/resource/locales/DataResourceBundle.properties
===================================================================
--- trunk/src/schmitzm/data/resource/locales/DataResourceBundle.properties	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/resource/locales/DataResourceBundle.properties	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,19 +1,48 @@
-# -----------------------------------------------------------
-# ------ Default Translations (english) for components ------
-# ------ in Package schmitzm.data                      ------
-# -----------------------------------------------------------
-
-RasterDim.GridWidth=Grid width
-RasterDim.GridHeight=Grid height
-RasterDim.CellWidth=Cell width
-RasterDim.CellHeight=Cell height
-RasterDim.SampleType=Grid sample type
-RasterDim.ErrorMess=${0} of '${1}' is incompatible to '${2}'...
-
-# --- Translations for RasterOperationTree / RasterOperationTreeParser
-RasterOperationTree.AllowedIdx=allowed: 0 to ${0}
-RasterOperationTree.NoneAllowed=none allowed
-RasterOperationTree.err.NonNumericResult=RasterCalculator can only handle numeric results: ${0}
-RasterOperationTree.err.FilterReferenceNotAllowed=Filter can only be applied on a raster reference
-RasterOperationTree.err.InvalidRasterReference=Invalid input raster reference '#${0}' (${1})
-RasterOperationTree.err.InvalidFilterReference=Invalid input filter reference 'F${0}' (${1})
+##########
+#Copyright (c) 2009 Martin O. J. Schmitz.
+#
+#This file is part of the SCHMITZM library - a collection of utility 
+#classes based on Java 1.6, focussing (not only) on Java Swing 
+#and the Geotools library.
+#
+#The SCHMITZM project is hosted at:
+#http://wald.intevation.org/projects/schmitzm/
+#
+#This program is free software; you can redistribute it and/or
+#modify it under the terms of the GNU Lesser General Public License
+#as published by the Free Software Foundation; either version 3
+#of the License, or (at your option) any later version.
+#
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+#
+#You should have received a copy of the GNU Lesser General Public License (license.txt)
+#along with this program; if not, write to the Free Software
+#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#or try this link: http://www.gnu.org/licenses/lgpl.html
+#
+#Contributors:
+#    Martin O. J. Schmitz - initial API and implementation
+#    Stefan A. Krüger - additional utility classes
+##########
+# -----------------------------------------------------------
+# ------ Default Translations (english) for components ------
+# ------ in Package schmitzm.data                      ------
+# -----------------------------------------------------------
+
+RasterDim.GridWidth=Grid width
+RasterDim.GridHeight=Grid height
+RasterDim.CellWidth=Cell width
+RasterDim.CellHeight=Cell height
+RasterDim.SampleType=Grid sample type
+RasterDim.ErrorMess=${0} of '${1}' is incompatible to '${2}'...
+
+# --- Translations for RasterOperationTree / RasterOperationTreeParser
+RasterOperationTree.AllowedIdx=allowed: 0 to ${0}
+RasterOperationTree.NoneAllowed=none allowed
+RasterOperationTree.err.NonNumericResult=RasterCalculator can only handle numeric results: ${0}
+RasterOperationTree.err.FilterReferenceNotAllowed=Filter can only be applied on a raster reference
+RasterOperationTree.err.InvalidRasterReference=Invalid input raster reference '#${0}' (${1})
+RasterOperationTree.err.InvalidFilterReference=Invalid input filter reference 'F${0}' (${1})

Modified: trunk/src/schmitzm/data/resource/locales/DataResourceBundle_de.properties
===================================================================
--- trunk/src/schmitzm/data/resource/locales/DataResourceBundle_de.properties	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/data/resource/locales/DataResourceBundle_de.properties	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,19 +1,48 @@
-# ------------------------------------------------
-# ------ German Translations for components ------
-# ------ in Package schmitzm.data           ------
-# ------------------------------------------------
-
-RasterDim.GridWidth=Raster-Breite
-RasterDim.GridHeight=Raster-Hoehe
-RasterDim.CellWidth=Zellen-Breite
-RasterDim.CellHeight=Zellen-Hoehe
-RasterDim.SampleType=Raster-Datentyp
-RasterDim.ErrorMess=${0} von '${1}' ist nicht kompatibel zu '${2}'...
-
-# --- Translations for RasterOperationTree / RasterOperationTreeParser
-RasterOperationTree.AllowedIdx=erlaubt: 0 to ${0}
-RasterOperationTree.NoneAllowed=keine erlaubt
-RasterOperationTree.err.NonNumericResult=RasterCalculator kann nur numerische Ergebnisse verarbeiten: ${0}
-RasterOperationTree.err.FilterReferenceNotAllowed=Filter kann nur auf Raster-Referenzen angewandt werden
-RasterOperationTree.err.InvalidRasterReference=Ungültige Raster-Referenz '#${0}' (${1})
-RasterOperationTree.err.InvalidFilterReference=Ungültige Filter-Referenz 'F${0}' (${1})
+##########
+#Copyright (c) 2009 Martin O. J. Schmitz.
+#
+#This file is part of the SCHMITZM library - a collection of utility 
+#classes based on Java 1.6, focussing (not only) on Java Swing 
+#and the Geotools library.
+#
+#The SCHMITZM project is hosted at:
+#http://wald.intevation.org/projects/schmitzm/
+#
+#This program is free software; you can redistribute it and/or
+#modify it under the terms of the GNU Lesser General Public License
+#as published by the Free Software Foundation; either version 3
+#of the License, or (at your option) any later version.
+#
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+#
+#You should have received a copy of the GNU Lesser General Public License (license.txt)
+#along with this program; if not, write to the Free Software
+#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#or try this link: http://www.gnu.org/licenses/lgpl.html
+#
+#Contributors:
+#    Martin O. J. Schmitz - initial API and implementation
+#    Stefan A. Krüger - additional utility classes
+##########
+# ------------------------------------------------
+# ------ German Translations for components ------
+# ------ in Package schmitzm.data           ------
+# ------------------------------------------------
+
+RasterDim.GridWidth=Raster-Breite
+RasterDim.GridHeight=Raster-Hoehe
+RasterDim.CellWidth=Zellen-Breite
+RasterDim.CellHeight=Zellen-Hoehe
+RasterDim.SampleType=Raster-Datentyp
+RasterDim.ErrorMess=${0} von '${1}' ist nicht kompatibel zu '${2}'...
+
+# --- Translations for RasterOperationTree / RasterOperationTreeParser
+RasterOperationTree.AllowedIdx=erlaubt: 0 to ${0}
+RasterOperationTree.NoneAllowed=keine erlaubt
+RasterOperationTree.err.NonNumericResult=RasterCalculator kann nur numerische Ergebnisse verarbeiten: ${0}
+RasterOperationTree.err.FilterReferenceNotAllowed=Filter kann nur auf Raster-Referenzen angewandt werden
+RasterOperationTree.err.InvalidRasterReference=Ungültige Raster-Referenz '#${0}' (${1})
+RasterOperationTree.err.InvalidFilterReference=Ungültige Filter-Referenz 'F${0}' (${1})

Modified: trunk/src/schmitzm/geotools/FilterUtil.java
===================================================================
--- trunk/src/schmitzm/geotools/FilterUtil.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/FilterUtil.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,38 +1,67 @@
-package schmitzm.geotools;
-
-import org.geotools.factory.CommonFactoryFinder;
-import org.geotools.filter.Filter;
-import org.geotools.filter.FilterFactoryFinder;
-import org.geotools.filter.FilterFactoryImpl;
-import org.geotools.filter.visitor.DuplicatorFilterVisitor;
-import org.opengis.filter.FilterFactory2;
-
-import com.vividsolutions.jts.geom.GeometryFactory;
-
-
-/**
- * Diese Klasse enthaelt statische Helper-Methoden fuer die Arbeit mit
- * {@link Filter}.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * 
- * @version 1.01
- */
-public class FilterUtil {
-  /** Instanz von {@link FilterFactoryImpl}. */
-  public static final FilterFactoryImpl FILTER_FAC   = (FilterFactoryImpl)FilterFactoryFinder.createFilterFactory();
-  /** Globale Instanz von {@link FilterFactory2} **/
-  public static final FilterFactory2 FILTER_FAC2 = CommonFactoryFinder.getFilterFactory2(null);
-  /** Instanz von {@link GeometryFactory}. */
-  public static final GeometryFactory   GEOMETRY_FAC = new GeometryFactory();
-
-  /**
-   * Erzeugt eine Kopie eines Filters
-   * @param filter ein Filter
-   */
-  public static Filter cloneFilter(Filter filter) {
-    DuplicatorFilterVisitor dfv = new DuplicatorFilterVisitor(FILTER_FAC,false);
-    dfv.visit( filter );
-    Filter newFilter = (Filter)dfv.getCopy();
-    return newFilter;
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools;
+
+import org.geotools.factory.CommonFactoryFinder;
+import org.geotools.filter.Filter;
+import org.geotools.filter.FilterFactoryFinder;
+import org.geotools.filter.FilterFactoryImpl;
+import org.geotools.filter.visitor.DuplicatorFilterVisitor;
+import org.opengis.filter.FilterFactory2;
+
+import com.vividsolutions.jts.geom.GeometryFactory;
+
+
+/**
+ * Diese Klasse enthaelt statische Helper-Methoden fuer die Arbeit mit
+ * {@link Filter}.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * 
+ * @version 1.01
+ */
+public class FilterUtil {
+  /** Instanz von {@link FilterFactoryImpl}. */
+  public static final FilterFactoryImpl FILTER_FAC   = (FilterFactoryImpl)FilterFactoryFinder.createFilterFactory();
+  /** Globale Instanz von {@link FilterFactory2} **/
+  public static final FilterFactory2 FILTER_FAC2 = CommonFactoryFinder.getFilterFactory2(null);
+  /** Instanz von {@link GeometryFactory}. */
+  public static final GeometryFactory   GEOMETRY_FAC = new GeometryFactory();
+
+  /**
+   * Erzeugt eine Kopie eines Filters
+   * @param filter ein Filter
+   */
+  public static Filter cloneFilter(Filter filter) {
+    DuplicatorFilterVisitor dfv = new DuplicatorFilterVisitor(FILTER_FAC,false);
+    dfv.visit( filter );
+    Filter newFilter = (Filter)dfv.getCopy();
+    return newFilter;
+  }
+}

Modified: trunk/src/schmitzm/geotools/GTUtil.java
===================================================================
--- trunk/src/schmitzm/geotools/GTUtil.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/GTUtil.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,168 +1,186 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools;
-
-import java.awt.geom.Rectangle2D;
-import java.text.DecimalFormat;
-import java.util.Set;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-import org.apache.log4j.Logger;
-import org.geotools.geometry.Envelope2D;
-import org.geotools.geometry.jts.JTS;
-import org.geotools.referencing.CRS;
-import org.opengis.geometry.Envelope;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-
-/**
- * Diese Klasse enthaelt allgemeine Funktionen fuer die Arbeit mit Geotools.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class GTUtil {
-  private static Logger LOGGER = Logger.getLogger( GTUtil.class.getName() );
-
-  /** Konstante fuer das CRS "WGS84" (erzeugt als "EPSG:4326")*/
-  public static CoordinateReferenceSystem WGS84 = null;
-
-  // Initialisierung der CRS-Konstanten
-  static {
-    try {
-      WGS84 = CRS.decode("EPSG:4326",true); // lat/lon (WGS84)
-    } catch (Exception err) {
-    	LOGGER.warn("Exception while creating default WGS84 from code 'EPSG:4326'");
-    }
-  }
-
-  /**
-   * Erzeugt ein {@link CoordinateReferenceSystem} aus einer String-Definition.
-   * Akzeptiert wird ein EPSG-Code "EPSG:..." oder eine WKT-Definition des CRS
-   * @param crsDef Definition fuer das CRS.
-   * @return {@code null}, falls der String nicht zu einem CRS dekodiert werden
-   *         kann
-   */
-  public static CoordinateReferenceSystem createCRS(String crsDef) {
-    if ( crsDef == null || crsDef.trim().equals("") )
-      return null;
-
-    CoordinateReferenceSystem crs = null;
-    try {
-        // Akzeptiert wird: EPSG-Code
-        if (crsDef.startsWith("EPSG:"))
-          crs = createCRS_EPSG( crsDef );
-        else 
-          crs = CRS.parseWKT( crsDef );
-    } catch (Exception err) {
-      LOGGER.error("Error while creating CRS",err);
-    }
-    return crs;
-  }
-
-  /**
-   * Erzeugt ein {@link CoordinateReferenceSystem} aus einem (EPSG-)Code.
-   * Entspricht {@link CRS#decode(String,boolean) CRS#decode(String,true)}.
-   * Exceptions werden jedoch abgefangen und stattdessen {@code null} zurueckgegeben.
-   * @param code Code fuer das CRS.
-   */
-  public static CoordinateReferenceSystem createCRS_EPSG(String code) {
-    try {
-      return CRS.decode(code,true);
-    } catch (Exception err) {
-      LOGGER.error("Error while creating CRS",err);
-      return null;
-    }
-  }
-
-  /**
-   * Erzeugt ein UTM-CoordinateReferenceSystem.
-   * @param zone UTM-Zone
-   */
-  public static CoordinateReferenceSystem createCRS_UTM(int zone) {
-    DecimalFormat format_99 = new DecimalFormat("00");
-    return createCRS( "EPSG:326"+format_99.format(zone) );
-  }
-
-  /**
-   * Erzeugt einen {@link Envelope2D} aus einem {@link Rectangle2D} .
-   * @param env Georeferenz und Ausdehnung
-   * @param crs CoordinateReferenceSystem
-   */
-  public static Envelope2D createEnvelope2D(Rectangle2D env, CoordinateReferenceSystem crs) {
-    return new Envelope2D(crs, env.getX(), env.getY(), env.getWidth(),
-                          env.getHeight());
-  }
-
-  /**
-   * Liefert alle zur Verfuegung stehenden {@linkplain CoordinateReferenceSystem CRS} fuer eine
-   * Authority.
-   * @param authority      Authority fuer die die CRS geliefert werden (z.B. {@code "EPSG"})
-   * @param longitudeFirst {@code true} erzwingt die Achsenordnung (longitude, latitude). Siehe
-   *                       {@link CRS#decode(String, boolean)} (Bemerkung: {@code false} bedeutet
-   *                       System-Default, <b>nicht</b> (latitude, longitude)!)
-   * @param suppressWarnings wenn {@code true} werden Warnmeldungen unterdrueckt
-   * @return eine nach dem CRS-Namen geordnete Map
-   */
-  public static final SortedMap<String,CoordinateReferenceSystem> getAvailableCRSByName(String authority, boolean longitudeFirst, boolean suppressWarnings) {
-    SortedMap<String,CoordinateReferenceSystem> mapByCode = getAvailableCRSByCode(authority, longitudeFirst, suppressWarnings);
-    TreeMap<String,CoordinateReferenceSystem>   mapByName = new TreeMap<String, CoordinateReferenceSystem>();
-    for (String code : mapByCode.keySet()) {
-      CoordinateReferenceSystem crs = mapByCode.get(code);
-      mapByName.put( crs.getName().toString()+" ["+code+"]", crs );
-    }
-    return mapByName;
-  }
-
-  /**
-   * Liefert alle zur Verfuegung stehenden {@linkplain CoordinateReferenceSystem CRS} fuer eine
-   * Authority.
-   * @param authority      Authority fuer die die CRS geliefert werden (z.B. {@code "EPSG"})
-   * @param longitudeFirst {@code true} erzwingt die Achsenordnung (longitude, latitude). Siehe
-   *                       {@link CRS#decode(String, boolean)} (Bemerkung: {@code false} bedeutet
-   *                       System-Default, <b>nicht</b> (latitude, longitude)!)
-   * @param suppressWarnings wenn {@code true} werden Warnmeldungen unterdrueckt
-   * @return eine nach dem CRS-Code geordnete Map
-   */
-  public static final SortedMap<String,CoordinateReferenceSystem> getAvailableCRSByCode(String authority, boolean longitudeFirst, boolean suppressWarnings) {
-    TreeMap<String,CoordinateReferenceSystem> map = new TreeMap<String, CoordinateReferenceSystem>();
-    for (String code : (Set<String>)CRS.getSupportedCodes(authority)) {
-      if ( !code.startsWith(authority) )
-        code = authority + ":" + code;
-      try {
-        CoordinateReferenceSystem crs = CRS.decode(code, longitudeFirst);
-        map.put(code, crs);
-      } catch (Exception err) {
-        if ( !suppressWarnings )
-          LOGGER.warn("CRS could not be decoded: "+code);
-      }
-    }
-    return map;
-  }
-
-  /**
-   * Berechnet den Schnitt zweier {@link Envelope Envelopes}.
-   * @param env1 erster Envelope
-   * @param env2 zweiter Envelope
-   * @param crs  {@link CoordinateReferenceSystem} fuer den Schnitt-Envelope
-   */
-  public static Envelope intersectEnvelope(Envelope env1, Envelope env2, CoordinateReferenceSystem crs) {
-    // Envelopes in JTS umwandeln
-    com.vividsolutions.jts.geom.Envelope env1JTS = new com.vividsolutions.jts.geom.Envelope(
-      env1.getMinimum(0),env1.getMaximum(0),env1.getMinimum(1),env1.getMaximum(1));
-    com.vividsolutions.jts.geom.Envelope env2JTS = new com.vividsolutions.jts.geom.Envelope(
-      env2.getMinimum(0),env2.getMaximum(0),env2.getMinimum(1),env2.getMaximum(1));
-    com.vividsolutions.jts.geom.Envelope intersetionEnvJTS = env1JTS.intersection(env2JTS);
-    // Subset nur bzgl. des Bereichs in dem auch das Raster liegt
-    return JTS.getEnvelope2D(intersetionEnvJTS,crs);
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools;
+
+import java.awt.geom.Rectangle2D;
+import java.text.DecimalFormat;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.apache.log4j.Logger;
+import org.geotools.geometry.Envelope2D;
+import org.geotools.geometry.jts.JTS;
+import org.geotools.referencing.CRS;
+import org.opengis.geometry.Envelope;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+
+/**
+ * Diese Klasse enthaelt allgemeine Funktionen fuer die Arbeit mit Geotools.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class GTUtil {
+  private static Logger LOGGER = Logger.getLogger( GTUtil.class.getName() );
+
+  /** Konstante fuer das CRS "WGS84" (erzeugt als "EPSG:4326")*/
+  public static CoordinateReferenceSystem WGS84 = null;
+
+  // Initialisierung der CRS-Konstanten
+  static {
+    try {
+      WGS84 = CRS.decode("EPSG:4326",true); // lat/lon (WGS84)
+    } catch (Exception err) {
+    	LOGGER.warn("Exception while creating default WGS84 from code 'EPSG:4326'");
+    }
+  }
+
+  /**
+   * Erzeugt ein {@link CoordinateReferenceSystem} aus einer String-Definition.
+   * Akzeptiert wird ein EPSG-Code "EPSG:..." oder eine WKT-Definition des CRS
+   * @param crsDef Definition fuer das CRS.
+   * @return {@code null}, falls der String nicht zu einem CRS dekodiert werden
+   *         kann
+   */
+  public static CoordinateReferenceSystem createCRS(String crsDef) {
+    if ( crsDef == null || crsDef.trim().equals("") )
+      return null;
+
+    CoordinateReferenceSystem crs = null;
+    try {
+        // Akzeptiert wird: EPSG-Code
+        if (crsDef.startsWith("EPSG:"))
+          crs = createCRS_EPSG( crsDef );
+        else 
+          crs = CRS.parseWKT( crsDef );
+    } catch (Exception err) {
+      LOGGER.error("Error while creating CRS",err);
+    }
+    return crs;
+  }
+
+  /**
+   * Erzeugt ein {@link CoordinateReferenceSystem} aus einem (EPSG-)Code.
+   * Entspricht {@link CRS#decode(String,boolean) CRS#decode(String,true)}.
+   * Exceptions werden jedoch abgefangen und stattdessen {@code null} zurueckgegeben.
+   * @param code Code fuer das CRS.
+   */
+  public static CoordinateReferenceSystem createCRS_EPSG(String code) {
+    try {
+      return CRS.decode(code,true);
+    } catch (Exception err) {
+      LOGGER.error("Error while creating CRS",err);
+      return null;
+    }
+  }
+
+  /**
+   * Erzeugt ein UTM-CoordinateReferenceSystem.
+   * @param zone UTM-Zone
+   */
+  public static CoordinateReferenceSystem createCRS_UTM(int zone) {
+    DecimalFormat format_99 = new DecimalFormat("00");
+    return createCRS( "EPSG:326"+format_99.format(zone) );
+  }
+
+  /**
+   * Erzeugt einen {@link Envelope2D} aus einem {@link Rectangle2D} .
+   * @param env Georeferenz und Ausdehnung
+   * @param crs CoordinateReferenceSystem
+   */
+  public static Envelope2D createEnvelope2D(Rectangle2D env, CoordinateReferenceSystem crs) {
+    return new Envelope2D(crs, env.getX(), env.getY(), env.getWidth(),
+                          env.getHeight());
+  }
+
+  /**
+   * Liefert alle zur Verfuegung stehenden {@linkplain CoordinateReferenceSystem CRS} fuer eine
+   * Authority.
+   * @param authority      Authority fuer die die CRS geliefert werden (z.B. {@code "EPSG"})
+   * @param longitudeFirst {@code true} erzwingt die Achsenordnung (longitude, latitude). Siehe
+   *                       {@link CRS#decode(String, boolean)} (Bemerkung: {@code false} bedeutet
+   *                       System-Default, <b>nicht</b> (latitude, longitude)!)
+   * @param suppressWarnings wenn {@code true} werden Warnmeldungen unterdrueckt
+   * @return eine nach dem CRS-Namen geordnete Map
+   */
+  public static final SortedMap<String,CoordinateReferenceSystem> getAvailableCRSByName(String authority, boolean longitudeFirst, boolean suppressWarnings) {
+    SortedMap<String,CoordinateReferenceSystem> mapByCode = getAvailableCRSByCode(authority, longitudeFirst, suppressWarnings);
+    TreeMap<String,CoordinateReferenceSystem>   mapByName = new TreeMap<String, CoordinateReferenceSystem>();
+    for (String code : mapByCode.keySet()) {
+      CoordinateReferenceSystem crs = mapByCode.get(code);
+      mapByName.put( crs.getName().toString()+" ["+code+"]", crs );
+    }
+    return mapByName;
+  }
+
+  /**
+   * Liefert alle zur Verfuegung stehenden {@linkplain CoordinateReferenceSystem CRS} fuer eine
+   * Authority.
+   * @param authority      Authority fuer die die CRS geliefert werden (z.B. {@code "EPSG"})
+   * @param longitudeFirst {@code true} erzwingt die Achsenordnung (longitude, latitude). Siehe
+   *                       {@link CRS#decode(String, boolean)} (Bemerkung: {@code false} bedeutet
+   *                       System-Default, <b>nicht</b> (latitude, longitude)!)
+   * @param suppressWarnings wenn {@code true} werden Warnmeldungen unterdrueckt
+   * @return eine nach dem CRS-Code geordnete Map
+   */
+  public static final SortedMap<String,CoordinateReferenceSystem> getAvailableCRSByCode(String authority, boolean longitudeFirst, boolean suppressWarnings) {
+    TreeMap<String,CoordinateReferenceSystem> map = new TreeMap<String, CoordinateReferenceSystem>();
+    for (String code : (Set<String>)CRS.getSupportedCodes(authority)) {
+      if ( !code.startsWith(authority) )
+        code = authority + ":" + code;
+      try {
+        CoordinateReferenceSystem crs = CRS.decode(code, longitudeFirst);
+        map.put(code, crs);
+      } catch (Exception err) {
+        if ( !suppressWarnings )
+          LOGGER.warn("CRS could not be decoded: "+code);
+      }
+    }
+    return map;
+  }
+
+  /**
+   * Berechnet den Schnitt zweier {@link Envelope Envelopes}.
+   * @param env1 erster Envelope
+   * @param env2 zweiter Envelope
+   * @param crs  {@link CoordinateReferenceSystem} fuer den Schnitt-Envelope
+   */
+  public static Envelope intersectEnvelope(Envelope env1, Envelope env2, CoordinateReferenceSystem crs) {
+    // Envelopes in JTS umwandeln
+    com.vividsolutions.jts.geom.Envelope env1JTS = new com.vividsolutions.jts.geom.Envelope(
+      env1.getMinimum(0),env1.getMaximum(0),env1.getMinimum(1),env1.getMaximum(1));
+    com.vividsolutions.jts.geom.Envelope env2JTS = new com.vividsolutions.jts.geom.Envelope(
+      env2.getMinimum(0),env2.getMaximum(0),env2.getMinimum(1),env2.getMaximum(1));
+    com.vividsolutions.jts.geom.Envelope intersetionEnvJTS = env1JTS.intersection(env2JTS);
+    // Subset nur bzgl. des Bereichs in dem auch das Raster liegt
+    return JTS.getEnvelope2D(intersetionEnvJTS,crs);
+  }
+
+}

Modified: trunk/src/schmitzm/geotools/JTSUtil.java
===================================================================
--- trunk/src/schmitzm/geotools/JTSUtil.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/JTSUtil.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,92 +1,110 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools;
-
-import org.apache.log4j.Logger;
-import org.geotools.geometry.jts.JTS;
-import org.geotools.referencing.CRS;
-import org.opengis.referencing.FactoryException;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-import org.opengis.referencing.operation.MathTransform;
-import org.opengis.referencing.operation.TransformException;
-
-import com.vividsolutions.jts.geom.Coordinate;
-import com.vividsolutions.jts.geom.Envelope;
-
-/**
- * Diese Klasse enthaelt allgemeine Funktionen fuer die Arbeit mit den
- * in Geotools verwendeten JTS-Komponenten vereinfacht.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.1
- */
-public class JTSUtil {
-  private static Logger LOGGER = Logger.getLogger( JTSUtil.class.getName() );
-
-  /**
-   * Created an (CRS-less) JTS-Envelope from an OpenGIS-Envelope.
-   * @param envelope an OpenGIS-Envelope
-   * @return an JTS-Envelope
-   */
-  public static Envelope createEnvelope(org.opengis.geometry.Envelope envelope) { // gt2-2.4.2
-//  public static Envelope createEnvelope(org.opengis.spatialschema.geometry.Envelope envelope) { // gt2-2.3.4
-    return new Envelope(
-      envelope.getMinimum(0), // X1
-      envelope.getMaximum(0), // X2
-      envelope.getMinimum(1), // Y1
-      envelope.getMaximum(1)  // Y2
-    );
-  }
-
-  /**
-   * Transformiert einen JTS-Envelope von einem CRS in ein anderes.
-   * @param sourceEnv JTS-Envelope
-   * @param sourceCRS CRS von {@code sourceEnv}
-   * @param destCRS   CRS in das umgerechnet werden soll
-   * @see CRS#findMathTransform(CoordinateReferenceSystem,CoordinateReferenceSystem)
-   * @see JTS#transform(Envelope,MathTransform)
-   */
-  public static Envelope transformEnvelope(Envelope sourceEnv, CoordinateReferenceSystem sourceCRS, CoordinateReferenceSystem destCRS) {
-    Envelope destEnv = null;
-      MathTransform transform;
-	try {
-		transform = CRS.findMathTransform(sourceCRS, destCRS);
-		destEnv = JTS.transform(sourceEnv,transform);
-	} catch (FactoryException e) {
-		LOGGER.warn("CRS tranformation for JTS envelope not successfully",e);
-	} catch (TransformException e) {
-		LOGGER.warn("CRS tranformation for JTS envelope not successfully",e);
-	}
-    return destEnv;
-  }
-
-  /**
-   * Transformiert eine Koordinate von einem CRS in ein anderes.
-   * @param sourceCoord Koordinate
-   * @param sourceCRS   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 Coordinate transformCoordinate(Coordinate sourceCoord, CoordinateReferenceSystem sourceCRS, CoordinateReferenceSystem destCRS) {
-    Coordinate destCoord = null;
-    MathTransform transform;
-    try {
-        transform = CRS.findMathTransform(sourceCRS, destCRS);
-        destCoord = JTS.transform(sourceCoord,null,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 destCoord;
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools;
+
+import org.apache.log4j.Logger;
+import org.geotools.geometry.jts.JTS;
+import org.geotools.referencing.CRS;
+import org.opengis.referencing.FactoryException;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.operation.MathTransform;
+import org.opengis.referencing.operation.TransformException;
+
+import com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.Envelope;
+
+/**
+ * Diese Klasse enthaelt allgemeine Funktionen fuer die Arbeit mit den
+ * in Geotools verwendeten JTS-Komponenten vereinfacht.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.1
+ */
+public class JTSUtil {
+  private static Logger LOGGER = Logger.getLogger( JTSUtil.class.getName() );
+
+  /**
+   * Created an (CRS-less) JTS-Envelope from an OpenGIS-Envelope.
+   * @param envelope an OpenGIS-Envelope
+   * @return an JTS-Envelope
+   */
+  public static Envelope createEnvelope(org.opengis.geometry.Envelope envelope) { // gt2-2.4.2
+//  public static Envelope createEnvelope(org.opengis.spatialschema.geometry.Envelope envelope) { // gt2-2.3.4
+    return new Envelope(
+      envelope.getMinimum(0), // X1
+      envelope.getMaximum(0), // X2
+      envelope.getMinimum(1), // Y1
+      envelope.getMaximum(1)  // Y2
+    );
+  }
+
+  /**
+   * Transformiert einen JTS-Envelope von einem CRS in ein anderes.
+   * @param sourceEnv JTS-Envelope
+   * @param sourceCRS CRS von {@code sourceEnv}
+   * @param destCRS   CRS in das umgerechnet werden soll
+   * @see CRS#findMathTransform(CoordinateReferenceSystem,CoordinateReferenceSystem)
+   * @see JTS#transform(Envelope,MathTransform)
+   */
+  public static Envelope transformEnvelope(Envelope sourceEnv, CoordinateReferenceSystem sourceCRS, CoordinateReferenceSystem destCRS) {
+    Envelope destEnv = null;
+      MathTransform transform;
+	try {
+		transform = CRS.findMathTransform(sourceCRS, destCRS);
+		destEnv = JTS.transform(sourceEnv,transform);
+	} catch (FactoryException e) {
+		LOGGER.warn("CRS tranformation for JTS envelope not successfully",e);
+	} catch (TransformException e) {
+		LOGGER.warn("CRS tranformation for JTS envelope not successfully",e);
+	}
+    return destEnv;
+  }
+
+  /**
+   * Transformiert eine Koordinate von einem CRS in ein anderes.
+   * @param sourceCoord Koordinate
+   * @param sourceCRS   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 Coordinate transformCoordinate(Coordinate sourceCoord, CoordinateReferenceSystem sourceCRS, CoordinateReferenceSystem destCRS) {
+    Coordinate destCoord = null;
+    MathTransform transform;
+    try {
+        transform = CRS.findMathTransform(sourceCRS, destCRS);
+        destCoord = JTS.transform(sourceCoord,null,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 destCoord;
+  }
+}

Modified: trunk/src/schmitzm/geotools/feature/AbstractAutoValueGenerator.java
===================================================================
--- trunk/src/schmitzm/geotools/feature/AbstractAutoValueGenerator.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/feature/AbstractAutoValueGenerator.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,57 +1,76 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.geotools.feature;
-
-import org.geotools.feature.AttributeType;
-
-/**
- * This interface represents a generator to create an attribute default
- * value individually.
- * @see FeatureUtil#registerAutoValueGenerator(AttributeType, AutoValueGenerator)
- * @see FeatureUtil#getAutoValueGenerator(AttributeType)
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- */
-public abstract class AbstractAutoValueGenerator<E> implements AutoValueGenerator<E> {
-  /** Holds the first value generated by {@link #generateNextValue()}. */
-  protected E firstValue;
-
-  /** Holds the last value generated by {@link #generateNextValue()}. */
-  protected E lastValue;
-
-  /**
-   * Creates a new generator.
-   */
-  public AbstractAutoValueGenerator() {
-    this(null);
-  }
-
-  /**
-   * Creates a new generator.
-   * @param firstValue first value generated by {@link #generateNextValue()}
-   */
-  public AbstractAutoValueGenerator(E firstValue) {
-    resetAutoValue(firstValue);
-  }
-
-  /**
-   * Resets the generator, so the next {@link #generateNextValue()} call
-   * generates {@code firstValue} as auto value.
-   * @param firstValue next value to generate (if {@code null} the
-   *                   first value is reset to a previous set first
-   *                   value)
-   */
-  public void resetAutoValue(E firstValue) {
-    if ( firstValue != null )
-      this.firstValue = firstValue;
-    this.lastValue  = null;
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.feature;
+
+import org.geotools.feature.AttributeType;
+
+/**
+ * This interface represents a generator to create an attribute default
+ * value individually.
+ * @see FeatureUtil#registerAutoValueGenerator(AttributeType, AutoValueGenerator)
+ * @see FeatureUtil#getAutoValueGenerator(AttributeType)
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ */
+public abstract class AbstractAutoValueGenerator<E> implements AutoValueGenerator<E> {
+  /** Holds the first value generated by {@link #generateNextValue()}. */
+  protected E firstValue;
+
+  /** Holds the last value generated by {@link #generateNextValue()}. */
+  protected E lastValue;
+
+  /**
+   * Creates a new generator.
+   */
+  public AbstractAutoValueGenerator() {
+    this(null);
+  }
+
+  /**
+   * Creates a new generator.
+   * @param firstValue first value generated by {@link #generateNextValue()}
+   */
+  public AbstractAutoValueGenerator(E firstValue) {
+    resetAutoValue(firstValue);
+  }
+
+  /**
+   * Resets the generator, so the next {@link #generateNextValue()} call
+   * generates {@code firstValue} as auto value.
+   * @param firstValue next value to generate (if {@code null} the
+   *                   first value is reset to a previous set first
+   *                   value)
+   */
+  public void resetAutoValue(E firstValue) {
+    if ( firstValue != null )
+      this.firstValue = firstValue;
+    this.lastValue  = null;
+  }
+
+}

Modified: trunk/src/schmitzm/geotools/feature/AttributeFilter.java
===================================================================
--- trunk/src/schmitzm/geotools/feature/AttributeFilter.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/feature/AttributeFilter.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,204 +1,233 @@
-package schmitzm.geotools.feature;
-
-import org.geotools.feature.Feature;
-import org.geotools.filter.AbstractFilterImpl;
-import org.geotools.filter.Filter;
-import org.geotools.filter.FilterFactoryImpl;
-
-/**
- * Diese Klasse stellt einen {@link Filter} dar, der einen Attributwert mit einem
- * konstanten Vergleichswert vergleicht.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class AttributeFilter extends AbstractFilterImpl implements Cloneable {
-  /** Attribut-Filter, der auf "Attributwert = Konstante" prueft. */
-  public static final AttributeFilter EQUALS = new AttributeFilter(CompareType.EQUALS);
-  /** Attribut-Filter, der auf "Attributwert > Konstante" prueft. */
-  public static final AttributeFilter GT = new AttributeFilter(CompareType.GT);
-  /** Attribut-Filter, der auf "Attributwert >= Konstante" prueft. */
-  public static final AttributeFilter GE = new AttributeFilter(CompareType.GE);
-  /** Attribut-Filter, der auf "Attributwert < Konstante" prueft. */
-  public static final AttributeFilter LT = new AttributeFilter(CompareType.LT);
-  /** Attribut-Filter, der auf "Attributwert <= Konstante" prueft. */
-  public static final AttributeFilter LE = new AttributeFilter(CompareType.LE);
-
-  /** Typ der Vergleichsfunktion fuer den Filter. */
-  public static enum CompareType {
-    /** Vergleich auf Gleichheit (Attributwert = Konstante). */
-    EQUALS,
-    /** Groesser-Vergleich (Attributwert > Konstante). */
-    GT,
-    /** Groesser/Gleich-Vergleich (Attributwert >= Konstante). */
-    GE,
-    /** Kleiner-Vergleich (Attributwert < Konstante). */
-    LT,
-    /** Kleiner/Gleich-Vergleich (Attributwert <= Konstante). */
-    LE,
-  }
-
-  /** Art des Vergleichs in {@link #evaluate(Feature)}. */
-  protected CompareType compType = null;
-  /** Name des Feature-Attributs, das mit der {@linkplain #compValue Konstante}
-   *  verglichen wird.*/
-  protected String attrName = "";
-  /** Konstante, mit der das {@linkplain #attrName Feature-Attibut}
-   *  vergleichen wird. */
-  protected Object compValue = null;
-
-  /**
-   * Erzeugt einen neuen Filter. Das Attribut und die Konstante muessen
-   * nachtraeglich durch {@link #setAttributeName(String)} und
-   * {@link #setCompareValue(Object)} gesetzt werden.
-   * @param compType bestimmt die Vergleichs-Funktion
-   * @see #CompareType
-   */
-  public AttributeFilter(CompareType compType) {
-    this(compType, null, null);
-  }
-
-  /**
-   * Erzeugt einen neuen Filter.
-   * @param compType bestimmt die Vergleichs-Funktion
-   * @param attrName Name des Attributs, welches verglichen wird
-   * @param compValue Konstante mit der das Attribut verglichen wird
-   */
-  public AttributeFilter(CompareType compType, String attrName, Object compValue) {
-    super( new FilterFactoryImpl() );
-    this.compType = compType;
-    setAttributeName(attrName);
-    setCompareValue(compValue);
-  }
-
-  /**
-   * Liefert einen Filter, der die inverse Funktion des Filters darstellt.
-   */
-  public AttributeFilter inverse() {
-    switch ( compType ) {
-      case EQUALS: return EQUALS;
-      case GT:     return LE;
-      case GE:     return LT;
-      case LT:     return GE;
-      case LE:     return GT;
-    }
-    throw new UnsupportedOperationException("Compare type can not be inverted: "+compType);
-  }
-
-  /**
-   * Setzt die Konstante, mit der der Attribut-Wert verglichen wird.
-   * @param compValue Vergleichswert
-   */
-  public void setCompareValue(Object compValue) {
-    this.compValue = compValue;
-  }
-
-  /**
-   * Liefert die Konstante, mit der der Attribut-Wert verglichen wird.
-   */
-  public Object getCompareValue() {
-    return this.compValue;
-  }
-
-  /**
-   * Setzt das Attribut, das mit der Konstanten verglichen wird.
-   * @param attrName Attribut-Name
-   */
-  public void setAttributeName(String attrName) {
-    this.attrName = attrName;
-  }
-
-  /**
-   * Liefert das Attribut, das mit der Konstanten verglichen wird.
-   */
-  public Object getAttributeName() {
-    return this.attrName;
-  }
-
-  /**
-   * Liefert den Vergleichstype mit dem das Attribut und die Konstanten
-   * verglichen werden.
-   */
-  public CompareType getCompareType() {
-    return this.compType;
-  }
-
-  /**
-   * Fuehrt den Vergleich durch. Liefert {@code false}, wenn der Attribut-Name
-   * oder die Konstante nicht gesetzt ist oder der Attribut-Wert {@code null} ist.
-   * @param feature Feature dessen Attribut mit der Konstanten verglichen wird
-   */
-  public boolean evaluate(Feature feature) {
-    if ( attrName == null || compValue == null )
-      return false;
-    Object attrValue = feature.getAttribute(attrName);
-    if ( attrValue == null )
-      return false;
-
-    Object attributeValue = attrValue;
-    Object compareValue   = compValue;
-    // Wenn Attribut- und Vergleichswert numerisch sind, dann werden die
-    // Zahlen vergleichen
-    if ( attrValue instanceof Number && compValue instanceof Number ) {
-      attributeValue = ((Number)attrValue).doubleValue();
-      compareValue   = ((Number)compValue).doubleValue();
-    } else if ( attrValue instanceof Number && compValue instanceof String ) {
-      // Versuchen, "compValue" in Zahl umzuwandeln
-      try {
-        compareValue   = Double.parseDouble( (String)compValue );
-        attributeValue = ((Number)attrValue).doubleValue();
-      } catch (NumberFormatException err) {
-      }
-    } else if ( attrValue instanceof String && compValue instanceof Number ) {
-      // Versuchen, "attrValue" in Zahl umzuwandeln
-      try {
-        attributeValue = Double.parseDouble( (String)attrValue );
-        compareValue   = ((Number)compValue).doubleValue();
-      } catch (NumberFormatException err) {
-      }
-    }
-
-    // Vergleich durchfuehren
-    switch( compType ) {
-      case EQUALS: return attributeValue.equals( compareValue );
-      case GT:
-      case GE:
-      case LT:
-      case LE: if ( !(attrValue instanceof Number) || !(compValue instanceof Number) )
-                 return false;
-               double aVal = (Double)attributeValue;
-               double cVal = (Double)compareValue;
-               switch (compType) {
-                 case GT: return aVal >  cVal;
-                 case GE: return aVal >= cVal;
-                 case LT: return aVal <  cVal;
-                 case LE: return aVal <= cVal;
-               }
-    }
-    // sollte nie erreicht werden
-    throw new UnsupportedOperationException("Unknown compare Type: "+compType);
-  }
-
-  /**
-   * Fuehrt den Vergleich durch. Liefert {@code false}, wenn der Attribut-Name
-   * oder die Konstante nicht gesetzt ist oder der Attribut-Wert {@code null} ist.
-   * @param feature Feature dessen Attribut mit der Konstanten verglichen wird
-   * @exception IllegalArgumentException wenn das uebergebene Objekt kein
-   *            {@link Feature} ist
-   */
-  public boolean evaluate(Object feature) {
-    if ( feature != null && !(feature instanceof Feature) )
-      throw new IllegalArgumentException("evaluate(Object) can only be appied ob Feature objects: "+feature.getClass().getSimpleName());
-    return evaluate((Feature)feature);
-  }
-
-  /**
-   * Erzeugt einen {@link AttributeFilter} mit dem gleichen Vergleichstyp,
-   * dem gleichen Attributnamen und der gleichen Vergleichskonstante wie
-   * die Instanz.
-   */
-  public AttributeFilter clone() {
-    return new AttributeFilter( compType, attrName, compValue );
-  }
-
-}
-
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.feature;
+
+import org.geotools.feature.Feature;
+import org.geotools.filter.AbstractFilterImpl;
+import org.geotools.filter.Filter;
+import org.geotools.filter.FilterFactoryImpl;
+
+/**
+ * Diese Klasse stellt einen {@link Filter} dar, der einen Attributwert mit einem
+ * konstanten Vergleichswert vergleicht.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class AttributeFilter extends AbstractFilterImpl implements Cloneable {
+  /** Attribut-Filter, der auf "Attributwert = Konstante" prueft. */
+  public static final AttributeFilter EQUALS = new AttributeFilter(CompareType.EQUALS);
+  /** Attribut-Filter, der auf "Attributwert > Konstante" prueft. */
+  public static final AttributeFilter GT = new AttributeFilter(CompareType.GT);
+  /** Attribut-Filter, der auf "Attributwert >= Konstante" prueft. */
+  public static final AttributeFilter GE = new AttributeFilter(CompareType.GE);
+  /** Attribut-Filter, der auf "Attributwert < Konstante" prueft. */
+  public static final AttributeFilter LT = new AttributeFilter(CompareType.LT);
+  /** Attribut-Filter, der auf "Attributwert <= Konstante" prueft. */
+  public static final AttributeFilter LE = new AttributeFilter(CompareType.LE);
+
+  /** Typ der Vergleichsfunktion fuer den Filter. */
+  public static enum CompareType {
+    /** Vergleich auf Gleichheit (Attributwert = Konstante). */
+    EQUALS,
+    /** Groesser-Vergleich (Attributwert > Konstante). */
+    GT,
+    /** Groesser/Gleich-Vergleich (Attributwert >= Konstante). */
+    GE,
+    /** Kleiner-Vergleich (Attributwert < Konstante). */
+    LT,
+    /** Kleiner/Gleich-Vergleich (Attributwert <= Konstante). */
+    LE,
+  }
+
+  /** Art des Vergleichs in {@link #evaluate(Feature)}. */
+  protected CompareType compType = null;
+  /** Name des Feature-Attributs, das mit der {@linkplain #compValue Konstante}
+   *  verglichen wird.*/
+  protected String attrName = "";
+  /** Konstante, mit der das {@linkplain #attrName Feature-Attibut}
+   *  vergleichen wird. */
+  protected Object compValue = null;
+
+  /**
+   * Erzeugt einen neuen Filter. Das Attribut und die Konstante muessen
+   * nachtraeglich durch {@link #setAttributeName(String)} und
+   * {@link #setCompareValue(Object)} gesetzt werden.
+   * @param compType bestimmt die Vergleichs-Funktion
+   * @see #CompareType
+   */
+  public AttributeFilter(CompareType compType) {
+    this(compType, null, null);
+  }
+
+  /**
+   * Erzeugt einen neuen Filter.
+   * @param compType bestimmt die Vergleichs-Funktion
+   * @param attrName Name des Attributs, welches verglichen wird
+   * @param compValue Konstante mit der das Attribut verglichen wird
+   */
+  public AttributeFilter(CompareType compType, String attrName, Object compValue) {
+    super( new FilterFactoryImpl() );
+    this.compType = compType;
+    setAttributeName(attrName);
+    setCompareValue(compValue);
+  }
+
+  /**
+   * Liefert einen Filter, der die inverse Funktion des Filters darstellt.
+   */
+  public AttributeFilter inverse() {
+    switch ( compType ) {
+      case EQUALS: return EQUALS;
+      case GT:     return LE;
+      case GE:     return LT;
+      case LT:     return GE;
+      case LE:     return GT;
+    }
+    throw new UnsupportedOperationException("Compare type can not be inverted: "+compType);
+  }
+
+  /**
+   * Setzt die Konstante, mit der der Attribut-Wert verglichen wird.
+   * @param compValue Vergleichswert
+   */
+  public void setCompareValue(Object compValue) {
+    this.compValue = compValue;
+  }
+
+  /**
+   * Liefert die Konstante, mit der der Attribut-Wert verglichen wird.
+   */
+  public Object getCompareValue() {
+    return this.compValue;
+  }
+
+  /**
+   * Setzt das Attribut, das mit der Konstanten verglichen wird.
+   * @param attrName Attribut-Name
+   */
+  public void setAttributeName(String attrName) {
+    this.attrName = attrName;
+  }
+
+  /**
+   * Liefert das Attribut, das mit der Konstanten verglichen wird.
+   */
+  public Object getAttributeName() {
+    return this.attrName;
+  }
+
+  /**
+   * Liefert den Vergleichstype mit dem das Attribut und die Konstanten
+   * verglichen werden.
+   */
+  public CompareType getCompareType() {
+    return this.compType;
+  }
+
+  /**
+   * Fuehrt den Vergleich durch. Liefert {@code false}, wenn der Attribut-Name
+   * oder die Konstante nicht gesetzt ist oder der Attribut-Wert {@code null} ist.
+   * @param feature Feature dessen Attribut mit der Konstanten verglichen wird
+   */
+  public boolean evaluate(Feature feature) {
+    if ( attrName == null || compValue == null )
+      return false;
+    Object attrValue = feature.getAttribute(attrName);
+    if ( attrValue == null )
+      return false;
+
+    Object attributeValue = attrValue;
+    Object compareValue   = compValue;
+    // Wenn Attribut- und Vergleichswert numerisch sind, dann werden die
+    // Zahlen vergleichen
+    if ( attrValue instanceof Number && compValue instanceof Number ) {
+      attributeValue = ((Number)attrValue).doubleValue();
+      compareValue   = ((Number)compValue).doubleValue();
+    } else if ( attrValue instanceof Number && compValue instanceof String ) {
+      // Versuchen, "compValue" in Zahl umzuwandeln
+      try {
+        compareValue   = Double.parseDouble( (String)compValue );
+        attributeValue = ((Number)attrValue).doubleValue();
+      } catch (NumberFormatException err) {
+      }
+    } else if ( attrValue instanceof String && compValue instanceof Number ) {
+      // Versuchen, "attrValue" in Zahl umzuwandeln
+      try {
+        attributeValue = Double.parseDouble( (String)attrValue );
+        compareValue   = ((Number)compValue).doubleValue();
+      } catch (NumberFormatException err) {
+      }
+    }
+
+    // Vergleich durchfuehren
+    switch( compType ) {
+      case EQUALS: return attributeValue.equals( compareValue );
+      case GT:
+      case GE:
+      case LT:
+      case LE: if ( !(attrValue instanceof Number) || !(compValue instanceof Number) )
+                 return false;
+               double aVal = (Double)attributeValue;
+               double cVal = (Double)compareValue;
+               switch (compType) {
+                 case GT: return aVal >  cVal;
+                 case GE: return aVal >= cVal;
+                 case LT: return aVal <  cVal;
+                 case LE: return aVal <= cVal;
+               }
+    }
+    // sollte nie erreicht werden
+    throw new UnsupportedOperationException("Unknown compare Type: "+compType);
+  }
+
+  /**
+   * Fuehrt den Vergleich durch. Liefert {@code false}, wenn der Attribut-Name
+   * oder die Konstante nicht gesetzt ist oder der Attribut-Wert {@code null} ist.
+   * @param feature Feature dessen Attribut mit der Konstanten verglichen wird
+   * @exception IllegalArgumentException wenn das uebergebene Objekt kein
+   *            {@link Feature} ist
+   */
+  public boolean evaluate(Object feature) {
+    if ( feature != null && !(feature instanceof Feature) )
+      throw new IllegalArgumentException("evaluate(Object) can only be appied ob Feature objects: "+feature.getClass().getSimpleName());
+    return evaluate((Feature)feature);
+  }
+
+  /**
+   * Erzeugt einen {@link AttributeFilter} mit dem gleichen Vergleichstyp,
+   * dem gleichen Attributnamen und der gleichen Vergleichskonstante wie
+   * die Instanz.
+   */
+  public AttributeFilter clone() {
+    return new AttributeFilter( compType, attrName, compValue );
+  }
+
+}
+

Modified: trunk/src/schmitzm/geotools/feature/AttributeTypeFilter.java
===================================================================
--- trunk/src/schmitzm/geotools/feature/AttributeTypeFilter.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/feature/AttributeTypeFilter.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,49 +1,78 @@
-package schmitzm.geotools.feature;
-
-import org.geotools.feature.AttributeType;
-import org.geotools.feature.type.GeometricAttributeType;
-
-import schmitzm.geotools.gui.FeatureFilterPanel;
-
-// fuer Doku
-
-/**
- * Dieses Interface definiert einen Filter fuer die Attribute eines
- * Features oder einer FeatureCollection. Hiermit lassen sich bestimmte Attribute
- * ausblenden, so dass z.B. die Geometrie eines Features nicht in einer
- * Tabelle dargestellt wird.
- * @see FeatureTypeTableModel
- * @see FeatureFilterPanel
- * @see FeatureCollectionPane
- * @see FeatureCollectionPane.FeatureCollectionTableModel
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public interface AttributeTypeFilter {
-
-  /**
-   * Standard-Filter, der alle Attribute akzeptiert.
-   */
-  public static final AttributeTypeFilter ALL = new AttributeTypeFilter() {
-    public boolean accept(AttributeType type, int idx) {
-      return true;
-    }
-  };
-
-  /**
-   * Standard-Filter, der {@linkplain GeometricAttributeType Geometrie-Attribute}
-   * ausblendet.
-   */
-  public static final AttributeTypeFilter NO_GEOMETRY = new AttributeTypeFilter() {
-    public boolean accept(AttributeType type, int idx) {
-      return !( type instanceof GeometricAttributeType );
-    }
-  };
-
-  /**
-   * Bestimmt, ob eine Attribut dargestellt wird, oder nicht.
-   * @param type ein Attribut-Typ
-   * @param idx  der Index des Attributs
-   */
-  public boolean accept(AttributeType type, int idx);
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.feature;
+
+import org.geotools.feature.AttributeType;
+import org.geotools.feature.type.GeometricAttributeType;
+
+import schmitzm.geotools.gui.FeatureFilterPanel;
+
+// fuer Doku
+
+/**
+ * Dieses Interface definiert einen Filter fuer die Attribute eines
+ * Features oder einer FeatureCollection. Hiermit lassen sich bestimmte Attribute
+ * ausblenden, so dass z.B. die Geometrie eines Features nicht in einer
+ * Tabelle dargestellt wird.
+ * @see FeatureTypeTableModel
+ * @see FeatureFilterPanel
+ * @see FeatureCollectionPane
+ * @see FeatureCollectionPane.FeatureCollectionTableModel
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public interface AttributeTypeFilter {
+
+  /**
+   * Standard-Filter, der alle Attribute akzeptiert.
+   */
+  public static final AttributeTypeFilter ALL = new AttributeTypeFilter() {
+    public boolean accept(AttributeType type, int idx) {
+      return true;
+    }
+  };
+
+  /**
+   * Standard-Filter, der {@linkplain GeometricAttributeType Geometrie-Attribute}
+   * ausblendet.
+   */
+  public static final AttributeTypeFilter NO_GEOMETRY = new AttributeTypeFilter() {
+    public boolean accept(AttributeType type, int idx) {
+      return !( type instanceof GeometricAttributeType );
+    }
+  };
+
+  /**
+   * Bestimmt, ob eine Attribut dargestellt wird, oder nicht.
+   * @param type ein Attribut-Typ
+   * @param idx  der Index des Attributs
+   */
+  public boolean accept(AttributeType type, int idx);
+}

Modified: trunk/src/schmitzm/geotools/feature/AutoValueGenerator.java
===================================================================
--- trunk/src/schmitzm/geotools/feature/AutoValueGenerator.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/feature/AutoValueGenerator.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,37 +1,56 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.geotools.feature;
-
-import org.geotools.feature.AttributeType;
-
-/**
- * This interface represents a generator to create an attribute default
- * value individually.
- * @see FeatureUtil#registerAutoValueGenerator(AttributeType, AutoValueGenerator)
- * @see FeatureUtil#getAutoValueGenerator(AttributeType)
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- */
-public interface AutoValueGenerator<E> {
-  /**
-   * Resets the generator, so the next {@link #generateNextValue()} call
-   * generates {@code firstValue} as auto value.
-   * @param firstValue next value to generate (if {@code null} the
-   *                   first value is reset to a previous set first
-   *                   value)
-   */
-  public void resetAutoValue(E firstValue);
-
-  /**
-   * Returns the next value.
-   */
-  public E getNextValue();
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.feature;
+
+import org.geotools.feature.AttributeType;
+
+/**
+ * This interface represents a generator to create an attribute default
+ * value individually.
+ * @see FeatureUtil#registerAutoValueGenerator(AttributeType, AutoValueGenerator)
+ * @see FeatureUtil#getAutoValueGenerator(AttributeType)
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ */
+public interface AutoValueGenerator<E> {
+  /**
+   * Resets the generator, so the next {@link #generateNextValue()} call
+   * generates {@code firstValue} as auto value.
+   * @param firstValue next value to generate (if {@code null} the
+   *                   first value is reset to a previous set first
+   *                   value)
+   */
+  public void resetAutoValue(E firstValue);
+
+  /**
+   * Returns the next value.
+   */
+  public E getNextValue();
+
+}

Modified: trunk/src/schmitzm/geotools/feature/FeatureCollectionReader.java
===================================================================
--- trunk/src/schmitzm/geotools/feature/FeatureCollectionReader.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/feature/FeatureCollectionReader.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,16 +1,34 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.feature;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.feature;
-
 import java.io.IOException;
 
 import org.geotools.data.FeatureReader;
@@ -19,74 +37,74 @@
 import org.geotools.feature.FeatureIterator;
 import org.geotools.feature.FeatureType;
 import org.geotools.feature.collection.FeatureIteratorImpl;
-
-/**
- * Diese Klasse implementiert einen {@link FeatureReader} ueber den
- * {@link FeatureIterator} einer {@link FeatureCollection}.<br>
- * <b>Beachte:</b><br>
- * Die <code>FeatureCollection</code> muss mindestens ein Element enthalten! Ansonsten
- * kann der {@link FeatureType} nicht ermittelt werden!
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class FeatureCollectionReader implements FeatureReader {
-  private FeatureIterator   iterator    = null;
-  private boolean           closed      = false;
-  private FeatureType       featureType = null;
-  private FeatureCollection fc          = null;
-
-  /**
-   * Erzeugt einen neuen FeatureReader.
-   * @param fc FeatureCollection aus der gelesen wird.
-   * @throws java.lang.UnsupportedOperationException falls die FeatureCollection
-   *         kein Element enthaelt.
-   */
-  public FeatureCollectionReader(FeatureCollection fc) {
-    if ( fc.isEmpty() )
-      throw new UnsupportedOperationException("FeatureCollection must contain at least one Feature!");
-    this.fc          = fc;
-    this.featureType = new FeatureIteratorImpl(fc).next().getFeatureType();
-    reset();
-  }
-
-  /**
-   * Liefert die Art der Features.
-   */
-  public FeatureType getFeatureType() {
-    return featureType;
-  }
-
-  /**
-   * Prueft, ob ein weiteres Feature gelesen werden kann.
-   */
-  public boolean hasNext() {
-    return !closed && iterator.hasNext();
-  }
-
-  /**
-   * Liefert das naechste Feature (aus der FeatureCollection).
-   * @exception IOException falls der Reader bereits geschlossen ist.
-   */
-  public Feature next() throws IOException {
-    if (closed)
-      throw new IOException("FeatureReader already closed!");
-    return iterator.next();
-  }
-
-  /**
-   * Schliesst den Reader. Danach koennen keine weiteren Features mehr
-   * gelesen werden. Ueber {@link #reset()} kann der Reader wieder geoeffnet
-   * werden.
-   */
-  public void close() {
-    closed = true;
-  }
-
-  /**
-   * Setzt den Reader auf den Anfang der {@link FeatureCollection} zurueck.
-   */
-  public void reset() {
-    this.closed = false;
-    this.iterator = new FeatureIteratorImpl(this.fc);
-  }
-}
+
+/**
+ * Diese Klasse implementiert einen {@link FeatureReader} ueber den
+ * {@link FeatureIterator} einer {@link FeatureCollection}.<br>
+ * <b>Beachte:</b><br>
+ * Die <code>FeatureCollection</code> muss mindestens ein Element enthalten! Ansonsten
+ * kann der {@link FeatureType} nicht ermittelt werden!
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class FeatureCollectionReader implements FeatureReader {
+  private FeatureIterator   iterator    = null;
+  private boolean           closed      = false;
+  private FeatureType       featureType = null;
+  private FeatureCollection fc          = null;
+
+  /**
+   * Erzeugt einen neuen FeatureReader.
+   * @param fc FeatureCollection aus der gelesen wird.
+   * @throws java.lang.UnsupportedOperationException falls die FeatureCollection
+   *         kein Element enthaelt.
+   */
+  public FeatureCollectionReader(FeatureCollection fc) {
+    if ( fc.isEmpty() )
+      throw new UnsupportedOperationException("FeatureCollection must contain at least one Feature!");
+    this.fc          = fc;
+    this.featureType = new FeatureIteratorImpl(fc).next().getFeatureType();
+    reset();
+  }
+
+  /**
+   * Liefert die Art der Features.
+   */
+  public FeatureType getFeatureType() {
+    return featureType;
+  }
+
+  /**
+   * Prueft, ob ein weiteres Feature gelesen werden kann.
+   */
+  public boolean hasNext() {
+    return !closed && iterator.hasNext();
+  }
+
+  /**
+   * Liefert das naechste Feature (aus der FeatureCollection).
+   * @exception IOException falls der Reader bereits geschlossen ist.
+   */
+  public Feature next() throws IOException {
+    if (closed)
+      throw new IOException("FeatureReader already closed!");
+    return iterator.next();
+  }
+
+  /**
+   * Schliesst den Reader. Danach koennen keine weiteren Features mehr
+   * gelesen werden. Ueber {@link #reset()} kann der Reader wieder geoeffnet
+   * werden.
+   */
+  public void close() {
+    closed = true;
+  }
+
+  /**
+   * Setzt den Reader auf den Anfang der {@link FeatureCollection} zurueck.
+   */
+  public void reset() {
+    this.closed = false;
+    this.iterator = new FeatureIteratorImpl(this.fc);
+  }
+}

Modified: trunk/src/schmitzm/geotools/feature/FeatureOperationTree.java
===================================================================
--- trunk/src/schmitzm/geotools/feature/FeatureOperationTree.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/feature/FeatureOperationTree.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,176 +1,194 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.feature;
-
-import org.geotools.feature.Feature;
-
-import schmitzm.lang.tree.BinaryTreeNode;
-import schmitzm.lang.tree.OperationTree;
-import schmitzm.lang.tree.TreeNode;
-
-/**
- * Diese Klasse stellt einen Operator-Baum dar, in dem neben den von der
- * Oberklasse definitierten Operationen, Referenzen auf {@link Feature}-Attribute
- * enthalten sein koennen. Der Operator-Baum wird auf einem einzelnen {@link Feature}
- * ausgewertet. <b>Zur Zeit koennen nur numerische Attribute referenziert werden
- * und keine Strings!</b><br>
- * <br>
- * <b>Referenz auf Attribut-Name:</b> {@link AttributeNameReferenceNode}<br>
- * Die Referenz auf einen Attribut-Namen wird durch einen {@code String}-Wert
- * dargestellt, der von einem {@code $} eingeleitet wird (z.B. {@code $citizens}).<br>
- * <br>
- * <b>Referenz auf Attribut-Index:</b> {@link AttributeIndexReferenceNode}<br>
- * Die Referenz auf einen Attribut-Index (beginnend bei 0) wird durch einen
- * {@code int}-Wert dargestellt, der von einem {@code #} eingeleitet wird (z.B. {@code #7}).<br>
- * <br>
- * Bei der Auswertung des Operatorbaums wird die Referenz durch
- * den entsprechenden Attribut-Wert des Features ersetzt.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class FeatureOperationTree extends OperationTree {
-  private Feature feature = null;
-
-  /**
-   * Erzeugt einen neuen Raster-Operatorbaum
-   * @param root Wurzelknoten
-   */
-  public FeatureOperationTree(TreeNode root) {
-    super(root);
-  }
-
-  /**
-   * Nicht unterstuetzt!
-   * @deprecated
-   * @exception UnsupportedOperationException bei jedem Aufruf
-   */
-  public Object evaluate() {
-    throw new UnsupportedOperationException("FeatureOperationTree only supports evaluate(Feature)");
-  }
-
-  /**
-   * Wertet den Operatorbaum auf einem {@link Feature} aus.
-   * @param feature ein Feature
-   */
-  public Object evaluate(Feature feature) {
-    this.feature = feature;
-    return super.evaluate();
-  }
-
-  /**
-   * Wertet einen Knoten des Operator-Baums aus.
-   * @param opTreeNode BinaryTreeNode
-   * @return double
-   */
-  protected Object evaluate(TreeNode opTreeNode) {
-    // Attribut-Index
-    if ( opTreeNode instanceof AttributeIndexReferenceNode ) {
-      int attrIdx = ((AttributeIndexReferenceNode)opTreeNode).getObject();
-      Object object = feature.getAttribute( attrIdx );
-      if ( object == null )
-        throw new UnsupportedOperationException( FeatureUtil.RESOURCE.getString("FeatureOperationTree.err.NullAttr",attrIdx) );
-//      if ( !(object instanceof Number) )
-//        throw new UnsupportedOperationException("FeatureOperationTree only can evaluate numeric Attributes: Attribute "+attrIdx+" is of type "+object.getClass().getSimpleName());
-//      return ((Number)object).doubleValue();
-      return object;
-    }
-
-    // Attribut-Name
-    if ( opTreeNode instanceof AttributeNameReferenceNode ) {
-      String attrName = ((AttributeNameReferenceNode)opTreeNode).getObject();
-      Object object = feature.getAttribute( attrName );
-      if ( feature.getFeatureType().getAttributeType( attrName ) == null )
-        throw new UnsupportedOperationException( FeatureUtil.RESOURCE.getString("FeatureOperationTree.err.UnknownAttr",attrName) );
-      if ( object == null )
-        throw new UnsupportedOperationException( FeatureUtil.RESOURCE.getString("FeatureOperationTree.err.NullAttr",attrName) );
-//      if ( !(object instanceof Number) )
-//        throw new UnsupportedOperationException("FeatureOperationTree can only evaluate numeric Attributes: '"+attrName+"' is of type "+object.getClass().getSimpleName());
-//      return ((Number)object).doubleValue();
-      return object;
-    }
-
-    return super.evaluate(opTreeNode);
-  }
-
-  /**
-   * Diese Knoten repraesentiert eine Namens-Referenz auf ein {@link Feature}-Attribut
-   * im Operatorbaum. Da es sich dabei um eine Konstante handelt, hat der Knoten
-   * keine Kind-Knoten. Die Referenz wird durch den Attribut-Namen ({@code String})
-   * dargestellt.
-   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-   * @version 1.0
-   */
-  public static class AttributeNameReferenceNode extends BinaryTreeNode<String> {
-    /**
-     * Erzeugt einen neuen Referenz-Knoten
-     * @param attrName Attribut-Name
-     * @param parent   Vater-Knoten
-     */
-    public AttributeNameReferenceNode(String attrName, BinaryTreeNode parent) {
-      super(attrName, parent);
-    }
-
-    /**
-     * Erzeugt einen neuen Referenz-Knoten
-     * @param attrName Attribut-Name
-     */
-    public AttributeNameReferenceNode(String attrName) {
-      this(attrName, null);
-    }
-
-    /**
-     * Macht nichts, da {@code AttributeReferenceNode} immer einen Blatt-Knoten
-     * darstellt.
-     * @param i Index (beginnend bei 0)
-     * @param child neuer Kind-Knoten
-     */
-    public void setChild(int i, TreeNode<String> child) {
-    }
-  }
-
-  /**
-   * Diese Knoten repraesentiert eine Index-Referenz auf ein {@link Feature}-Attribut
-   * im Operatorbaum. Da es sich dabei um eine Konstante handelt, hat der Knoten
-   * keine Kind-Knoten. Die Referenz wird durch den Attribut-Namen ({@code String})
-   * dargestellt.
-   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-   * @version 1.0
-   */
-  public static class AttributeIndexReferenceNode extends BinaryTreeNode<Integer> {
-    /**
-     * Erzeugt einen neuen Referenz-Knoten
-     * @param attrIdx  Attribut-Index (beginnend bei 0)
-     * @param parent   Vater-Knoten
-     */
-    public AttributeIndexReferenceNode(int attrIdx, BinaryTreeNode parent) {
-      super(attrIdx, parent);
-    }
-
-    /**
-     * Erzeugt einen neuen Referenz-Knoten
-     * @param attrIdx  Attribut-Index (beginnend bei 0)
-     */
-    public AttributeIndexReferenceNode(int attrIdx) {
-      this(attrIdx, null);
-    }
-
-    /**
-     * Macht nichts, da {@code AttributeIndexReferenceNode} immer einen Blatt-Knoten
-     * darstellt.
-     * @param i Index (beginnend bei 0)
-     * @param child neuer Kind-Knoten
-     */
-    public void setChild(int i, TreeNode<Integer> child) {
-    }
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.feature;
+
+import org.geotools.feature.Feature;
+
+import schmitzm.lang.tree.BinaryTreeNode;
+import schmitzm.lang.tree.OperationTree;
+import schmitzm.lang.tree.TreeNode;
+
+/**
+ * Diese Klasse stellt einen Operator-Baum dar, in dem neben den von der
+ * Oberklasse definitierten Operationen, Referenzen auf {@link Feature}-Attribute
+ * enthalten sein koennen. Der Operator-Baum wird auf einem einzelnen {@link Feature}
+ * ausgewertet. <b>Zur Zeit koennen nur numerische Attribute referenziert werden
+ * und keine Strings!</b><br>
+ * <br>
+ * <b>Referenz auf Attribut-Name:</b> {@link AttributeNameReferenceNode}<br>
+ * Die Referenz auf einen Attribut-Namen wird durch einen {@code String}-Wert
+ * dargestellt, der von einem {@code $} eingeleitet wird (z.B. {@code $citizens}).<br>
+ * <br>
+ * <b>Referenz auf Attribut-Index:</b> {@link AttributeIndexReferenceNode}<br>
+ * Die Referenz auf einen Attribut-Index (beginnend bei 0) wird durch einen
+ * {@code int}-Wert dargestellt, der von einem {@code #} eingeleitet wird (z.B. {@code #7}).<br>
+ * <br>
+ * Bei der Auswertung des Operatorbaums wird die Referenz durch
+ * den entsprechenden Attribut-Wert des Features ersetzt.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class FeatureOperationTree extends OperationTree {
+  private Feature feature = null;
+
+  /**
+   * Erzeugt einen neuen Raster-Operatorbaum
+   * @param root Wurzelknoten
+   */
+  public FeatureOperationTree(TreeNode root) {
+    super(root);
+  }
+
+  /**
+   * Nicht unterstuetzt!
+   * @deprecated
+   * @exception UnsupportedOperationException bei jedem Aufruf
+   */
+  public Object evaluate() {
+    throw new UnsupportedOperationException("FeatureOperationTree only supports evaluate(Feature)");
+  }
+
+  /**
+   * Wertet den Operatorbaum auf einem {@link Feature} aus.
+   * @param feature ein Feature
+   */
+  public Object evaluate(Feature feature) {
+    this.feature = feature;
+    return super.evaluate();
+  }
+
+  /**
+   * Wertet einen Knoten des Operator-Baums aus.
+   * @param opTreeNode BinaryTreeNode
+   * @return double
+   */
+  protected Object evaluate(TreeNode opTreeNode) {
+    // Attribut-Index
+    if ( opTreeNode instanceof AttributeIndexReferenceNode ) {
+      int attrIdx = ((AttributeIndexReferenceNode)opTreeNode).getObject();
+      Object object = feature.getAttribute( attrIdx );
+      if ( object == null )
+        throw new UnsupportedOperationException( FeatureUtil.RESOURCE.getString("FeatureOperationTree.err.NullAttr",attrIdx) );
+//      if ( !(object instanceof Number) )
+//        throw new UnsupportedOperationException("FeatureOperationTree only can evaluate numeric Attributes: Attribute "+attrIdx+" is of type "+object.getClass().getSimpleName());
+//      return ((Number)object).doubleValue();
+      return object;
+    }
+
+    // Attribut-Name
+    if ( opTreeNode instanceof AttributeNameReferenceNode ) {
+      String attrName = ((AttributeNameReferenceNode)opTreeNode).getObject();
+      Object object = feature.getAttribute( attrName );
+      if ( feature.getFeatureType().getAttributeType( attrName ) == null )
+        throw new UnsupportedOperationException( FeatureUtil.RESOURCE.getString("FeatureOperationTree.err.UnknownAttr",attrName) );
+      if ( object == null )
+        throw new UnsupportedOperationException( FeatureUtil.RESOURCE.getString("FeatureOperationTree.err.NullAttr",attrName) );
+//      if ( !(object instanceof Number) )
+//        throw new UnsupportedOperationException("FeatureOperationTree can only evaluate numeric Attributes: '"+attrName+"' is of type "+object.getClass().getSimpleName());
+//      return ((Number)object).doubleValue();
+      return object;
+    }
+
+    return super.evaluate(opTreeNode);
+  }
+
+  /**
+   * Diese Knoten repraesentiert eine Namens-Referenz auf ein {@link Feature}-Attribut
+   * im Operatorbaum. Da es sich dabei um eine Konstante handelt, hat der Knoten
+   * keine Kind-Knoten. Die Referenz wird durch den Attribut-Namen ({@code String})
+   * dargestellt.
+   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+   * @version 1.0
+   */
+  public static class AttributeNameReferenceNode extends BinaryTreeNode<String> {
+    /**
+     * Erzeugt einen neuen Referenz-Knoten
+     * @param attrName Attribut-Name
+     * @param parent   Vater-Knoten
+     */
+    public AttributeNameReferenceNode(String attrName, BinaryTreeNode parent) {
+      super(attrName, parent);
+    }
+
+    /**
+     * Erzeugt einen neuen Referenz-Knoten
+     * @param attrName Attribut-Name
+     */
+    public AttributeNameReferenceNode(String attrName) {
+      this(attrName, null);
+    }
+
+    /**
+     * Macht nichts, da {@code AttributeReferenceNode} immer einen Blatt-Knoten
+     * darstellt.
+     * @param i Index (beginnend bei 0)
+     * @param child neuer Kind-Knoten
+     */
+    public void setChild(int i, TreeNode<String> child) {
+    }
+  }
+
+  /**
+   * Diese Knoten repraesentiert eine Index-Referenz auf ein {@link Feature}-Attribut
+   * im Operatorbaum. Da es sich dabei um eine Konstante handelt, hat der Knoten
+   * keine Kind-Knoten. Die Referenz wird durch den Attribut-Namen ({@code String})
+   * dargestellt.
+   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+   * @version 1.0
+   */
+  public static class AttributeIndexReferenceNode extends BinaryTreeNode<Integer> {
+    /**
+     * Erzeugt einen neuen Referenz-Knoten
+     * @param attrIdx  Attribut-Index (beginnend bei 0)
+     * @param parent   Vater-Knoten
+     */
+    public AttributeIndexReferenceNode(int attrIdx, BinaryTreeNode parent) {
+      super(attrIdx, parent);
+    }
+
+    /**
+     * Erzeugt einen neuen Referenz-Knoten
+     * @param attrIdx  Attribut-Index (beginnend bei 0)
+     */
+    public AttributeIndexReferenceNode(int attrIdx) {
+      this(attrIdx, null);
+    }
+
+    /**
+     * Macht nichts, da {@code AttributeIndexReferenceNode} immer einen Blatt-Knoten
+     * darstellt.
+     * @param i Index (beginnend bei 0)
+     * @param child neuer Kind-Knoten
+     */
+    public void setChild(int i, TreeNode<Integer> child) {
+    }
+  }
+
+}

Modified: trunk/src/schmitzm/geotools/feature/FeatureOperationTreeFilter.java
===================================================================
--- trunk/src/schmitzm/geotools/feature/FeatureOperationTreeFilter.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/feature/FeatureOperationTreeFilter.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,95 +1,114 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.geotools.feature;
-
-import org.geotools.feature.Feature;
-import org.geotools.filter.AbstractFilterImpl;
-import org.geotools.filter.FilterFactoryImpl;
-
-/**
- * Dieser Filter nutzt einen {@link FeatureOperationTree}, um die
- * {@link #evaluate(Feature)}-Methode auszuwerten. Ein Feature erfuellt die
- * Filter-Bedingung, wenn das Ergebnis des auf dem Feature ausgewerteten
- * Operator-Baums ungleich 0 ist.
- * @see FeatureOperationTree
- * @see FeatureOperationTreeParser
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class FeatureOperationTreeFilter extends AbstractFilterImpl {
-  /** Formel, die auf dem Feature ausgewertet wird. */
-  protected String rule = null;
-  /** Operator-Baum zur Formel {@link #rule}. */
-  protected FeatureOperationTree opTree = null;
-
-  /**
-   * Erstellt einen neuen Filter.
-   * @param rule Formel, die auf dem Feature ausgewertet wird.
-   * @see FeatureOperationTreeParser
-   */
-  public FeatureOperationTreeFilter(String rule) {
-    this( rule, new FeatureOperationTreeParser() );
-  }
-
-  /**
-   * Erstellt einen neuen Filter.
-   * @param rule Formel, die auf dem Feature ausgewertet wird.
-   * @param parser Parser, der aus der Formel einen Operator-Baum erstellt
-   */
-  public FeatureOperationTreeFilter(String rule, FeatureOperationTreeParser parser) {
-    super( new FilterFactoryImpl() );
-    this.rule   = rule;
-    this.opTree = parser.parse(rule);
-  }
-
-  /**
-	 * Prueft, ob ein {@link Feature} dem Filter entspricht. Dies ist der Fall,
-	 * wenn das Formel-Ergebnis fuer das Feature ungleich 0 ist.
-	 * 
-	 * @param feature
-	 *            zu ueberpruefendes Feature
-	 * @return {@code true}, wenn das Feature dem Filter entspricht
-	 */
-	public boolean evaluate(Feature feature) {
-// Exception sollte hier nicht ausgegeben werden, da bei allgemeinen Fehlern
-// die Exception fuer JEDES Feature ausgegeben wuerde!	  
-//	  try{
-	    Object result = opTree.evaluate(feature);
-	    return result instanceof Boolean && (Boolean) result
-	        || result instanceof Number  && ((Number) result).doubleValue() != 0;
-//  	  } catch (Exception e){
-//  	    e.printStackTrace(); 
-//  	    return false;
-//  	  }
-	}
-
-  /**
-   * Prueft, ob ein {@link Feature} dem Filter entspricht. Dies ist der Fall,
-   * wenn das Formel-Ergebnis fuer das Feature ungleich 0 ist.
-   * @param feature zu ueberpruefendes Feature
-   * @return {@code true}, wenn die Auswertung
-   * @exception IllegalArgumentException wenn das uebergebene Objekt kein
-   *            {@link Feature} ist
-   */
-  public boolean evaluate(Object feature) {
-    if ( feature != null && !(feature instanceof Feature) )
-      throw new IllegalArgumentException("evaluate(Object) can only be applied to Feature objects: "+feature.getClass().getSimpleName());
-    return evaluate((Feature)feature);
-  }
-
-  /**
-   * Liefert die Formel, die den Filter definitiert.
-   */
-  public String getRule() {
-    return rule;
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.feature;
+
+import org.geotools.feature.Feature;
+import org.geotools.filter.AbstractFilterImpl;
+import org.geotools.filter.FilterFactoryImpl;
+
+/**
+ * Dieser Filter nutzt einen {@link FeatureOperationTree}, um die
+ * {@link #evaluate(Feature)}-Methode auszuwerten. Ein Feature erfuellt die
+ * Filter-Bedingung, wenn das Ergebnis des auf dem Feature ausgewerteten
+ * Operator-Baums ungleich 0 ist.
+ * @see FeatureOperationTree
+ * @see FeatureOperationTreeParser
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class FeatureOperationTreeFilter extends AbstractFilterImpl {
+  /** Formel, die auf dem Feature ausgewertet wird. */
+  protected String rule = null;
+  /** Operator-Baum zur Formel {@link #rule}. */
+  protected FeatureOperationTree opTree = null;
+
+  /**
+   * Erstellt einen neuen Filter.
+   * @param rule Formel, die auf dem Feature ausgewertet wird.
+   * @see FeatureOperationTreeParser
+   */
+  public FeatureOperationTreeFilter(String rule) {
+    this( rule, new FeatureOperationTreeParser() );
+  }
+
+  /**
+   * Erstellt einen neuen Filter.
+   * @param rule Formel, die auf dem Feature ausgewertet wird.
+   * @param parser Parser, der aus der Formel einen Operator-Baum erstellt
+   */
+  public FeatureOperationTreeFilter(String rule, FeatureOperationTreeParser parser) {
+    super( new FilterFactoryImpl() );
+    this.rule   = rule;
+    this.opTree = parser.parse(rule);
+  }
+
+  /**
+	 * Prueft, ob ein {@link Feature} dem Filter entspricht. Dies ist der Fall,
+	 * wenn das Formel-Ergebnis fuer das Feature ungleich 0 ist.
+	 * 
+	 * @param feature
+	 *            zu ueberpruefendes Feature
+	 * @return {@code true}, wenn das Feature dem Filter entspricht
+	 */
+	public boolean evaluate(Feature feature) {
+// Exception sollte hier nicht ausgegeben werden, da bei allgemeinen Fehlern
+// die Exception fuer JEDES Feature ausgegeben wuerde!	  
+//	  try{
+	    Object result = opTree.evaluate(feature);
+	    return result instanceof Boolean && (Boolean) result
+	        || result instanceof Number  && ((Number) result).doubleValue() != 0;
+//  	  } catch (Exception e){
+//  	    e.printStackTrace(); 
+//  	    return false;
+//  	  }
+	}
+
+  /**
+   * Prueft, ob ein {@link Feature} dem Filter entspricht. Dies ist der Fall,
+   * wenn das Formel-Ergebnis fuer das Feature ungleich 0 ist.
+   * @param feature zu ueberpruefendes Feature
+   * @return {@code true}, wenn die Auswertung
+   * @exception IllegalArgumentException wenn das uebergebene Objekt kein
+   *            {@link Feature} ist
+   */
+  public boolean evaluate(Object feature) {
+    if ( feature != null && !(feature instanceof Feature) )
+      throw new IllegalArgumentException("evaluate(Object) can only be applied to Feature objects: "+feature.getClass().getSimpleName());
+    return evaluate((Feature)feature);
+  }
+
+  /**
+   * Liefert die Formel, die den Filter definitiert.
+   */
+  public String getRule() {
+    return rule;
+  }
+
+}

Modified: trunk/src/schmitzm/geotools/feature/FeatureOperationTreeParser.java
===================================================================
--- trunk/src/schmitzm/geotools/feature/FeatureOperationTreeParser.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/feature/FeatureOperationTreeParser.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,70 +1,88 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.feature;
-
-import schmitzm.lang.tree.BinaryTreeNode;
-import schmitzm.lang.tree.OperationTreeParser;
-
-/**
- * Diese Klasse stellt einen Parser fuer einen {@linkplain FeatureOperationTree Feature-Operatorbaum}
- * dar. Dieser erstellt einen {@linkplain FeatureOperationTree Feature-Operatorbaum} aus einem
- * Formel-String, der neben den in {@link OperationTreeParser} beschriebenen
- * Komponenten Attribut-Referenzen enthalten darf.<br>
- * <br>
- * <b>Referenz auf Attribut-Name:</b> {@link FeatureOperationTree.AttributeNameReferenceNode}<br>
- * Die Referenz auf einen Attribut-Namen wird durch einen {@code String}-Wert
- * dargestellt, der von einem {@code $} eingeleitet wird (z.B. {@code $citizens}).<br>
- * <br>
- * <b>Referenz auf Attribut-Index:</b> {@link FeatureOperationTree.AttributeIndexReferenceNode}<br>
- * Die Referenz auf einen Attribut-Index (beginnend bei 0) wird durch einen
- * {@code int}-Wert dargestellt, der von einem {@code #} eingeleitet wird (z.B. {@code #7}).<br>
- * <br>
- * Bei der Auswertung des Operatorbaums wird die Referenz durch
- * den entsprechenden Attribut-Wert des Features ersetzt.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class FeatureOperationTreeParser extends OperationTreeParser {
-  /**
-   * Erstellt einen Feature-Operator-Baum aus einem Formel-String.
-   * @param rule Formel
-   */
-  public FeatureOperationTree parse(String rule) {
-    // Leere Formel wird als "immer wahr" behandelt
-    if ( rule == null || rule.trim().equals("") )
-      rule = "1";
-    return new FeatureOperationTree( super.parse(rule).getRoot() );
-  }
-
-  /**
-   * Parst das naechste Literal aus dem Tokenizer {@link #tok}.
-   * Erweitert die Funktionalitaet der Oberklasse, so dass neben Konstanten
-   * auch Referenznummern und -namen auf ein Feature-Attribut (eingeleitet
-   * durch {@code #} und {@code $}) angegeben werden koennen.
-   */
-  protected BinaryTreeNode parseLiteral() {
-    String token = nextNonWSToken();
-
-    // Attribut-Name
-    if (token.startsWith("$"))
-      return new FeatureOperationTree.AttributeNameReferenceNode(token.substring(1));
-
-    // Attribut-Index
-    if (token.startsWith("#"))
-      return new FeatureOperationTree.AttributeIndexReferenceNode(getIntFromString(token.substring(1)));
-
-    // sonst: auf Literale der Oberklasse zurueckgreifen
-    pushbackWithWSToken();
-    return super.parseLiteral();
-  }
-}
-
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.feature;
+
+import schmitzm.lang.tree.BinaryTreeNode;
+import schmitzm.lang.tree.OperationTreeParser;
+
+/**
+ * Diese Klasse stellt einen Parser fuer einen {@linkplain FeatureOperationTree Feature-Operatorbaum}
+ * dar. Dieser erstellt einen {@linkplain FeatureOperationTree Feature-Operatorbaum} aus einem
+ * Formel-String, der neben den in {@link OperationTreeParser} beschriebenen
+ * Komponenten Attribut-Referenzen enthalten darf.<br>
+ * <br>
+ * <b>Referenz auf Attribut-Name:</b> {@link FeatureOperationTree.AttributeNameReferenceNode}<br>
+ * Die Referenz auf einen Attribut-Namen wird durch einen {@code String}-Wert
+ * dargestellt, der von einem {@code $} eingeleitet wird (z.B. {@code $citizens}).<br>
+ * <br>
+ * <b>Referenz auf Attribut-Index:</b> {@link FeatureOperationTree.AttributeIndexReferenceNode}<br>
+ * Die Referenz auf einen Attribut-Index (beginnend bei 0) wird durch einen
+ * {@code int}-Wert dargestellt, der von einem {@code #} eingeleitet wird (z.B. {@code #7}).<br>
+ * <br>
+ * Bei der Auswertung des Operatorbaums wird die Referenz durch
+ * den entsprechenden Attribut-Wert des Features ersetzt.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class FeatureOperationTreeParser extends OperationTreeParser {
+  /**
+   * Erstellt einen Feature-Operator-Baum aus einem Formel-String.
+   * @param rule Formel
+   */
+  public FeatureOperationTree parse(String rule) {
+    // Leere Formel wird als "immer wahr" behandelt
+    if ( rule == null || rule.trim().equals("") )
+      rule = "1";
+    return new FeatureOperationTree( super.parse(rule).getRoot() );
+  }
+
+  /**
+   * Parst das naechste Literal aus dem Tokenizer {@link #tok}.
+   * Erweitert die Funktionalitaet der Oberklasse, so dass neben Konstanten
+   * auch Referenznummern und -namen auf ein Feature-Attribut (eingeleitet
+   * durch {@code #} und {@code $}) angegeben werden koennen.
+   */
+  protected BinaryTreeNode parseLiteral() {
+    String token = nextNonWSToken();
+
+    // Attribut-Name
+    if (token.startsWith("$"))
+      return new FeatureOperationTree.AttributeNameReferenceNode(token.substring(1));
+
+    // Attribut-Index
+    if (token.startsWith("#"))
+      return new FeatureOperationTree.AttributeIndexReferenceNode(getIntFromString(token.substring(1)));
+
+    // sonst: auf Literale der Oberklasse zurueckgreifen
+    pushbackWithWSToken();
+    return super.parseLiteral();
+  }
+}
+

Modified: trunk/src/schmitzm/geotools/feature/FeatureTableModel.java
===================================================================
--- trunk/src/schmitzm/geotools/feature/FeatureTableModel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/feature/FeatureTableModel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,178 +1,197 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.geotools.feature;
-
-import javax.swing.table.TableModel;
-
-import org.geotools.feature.AttributeType;
-import org.geotools.feature.Feature;
-import org.geotools.feature.FeatureType;
-
-import schmitzm.geotools.gui.GeotoolsGUIUtil;
-import schmitzm.swing.table.AbstractTableModel;
-import schmitzm.temp.BaseTypeUtil;
-
-/**
- * Diese Klasse stellt ein {@link TableModel} auf einem einzelnen {@link Feature}
- * dar. Dieses definiert drei Spalten:
- * <ol>
- *   <li>Attribut-Name</li>
- *   <li>Attribut-Typ</li>
- *   <li>Wert des Attributs als Text-Eingabe</li>
- * </ol>
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class FeatureTableModel extends AbstractTableModel {
-  /** {@link Feature} das in der Tabelle dargestellt wird. */
-  protected Feature feature = null;
-  /** {@link FeatureType} der in der Tabelle dargestellt wird. */
-  protected FeatureType featureType = null;
-
-  /**
-   * Erstellt ein leeres Tabellen-Modell.
-   */
-  public FeatureTableModel() {
-    this((Feature)null);
-  }
-
-  /**
-   * Erstellt ein neues Tabellen-Modell.
-   * @param feature dargestelltes Feature
-   */
-  public FeatureTableModel(Feature feature) {
-    this( feature != null ? feature.getFeatureType() : null);
-    setFeature( feature );
-  }
-
-  /**
-   * Erstellt ein neues Tabellen-Modell.
-   * @param type ein FeatureType
-   */
-  public FeatureTableModel(FeatureType type) {
-    super();
-    setFeature( type );
-  }
-
-  /**
-   * Setzt das {@link Feature}, das in der Tabelle dargestellt wird.
-   * @param feature {@link Feature}
-   */
-  public void setFeature(Feature feature) {
-    this.feature     = feature;
-    this.featureType = feature != null ? feature.getFeatureType() : null;
-    this.fireTableDataChanged();
-  }
-
-  /**
-   * Setzt das {@link Feature}, das in der Tabelle dargestellt wird.
-   * @param fType {@link FeatureType} fuer den eine Standard-Feature
-   *              angezeigt wird
-   */
-  public void setFeature(FeatureType fType) {
-    try {
-      if ( fType != null )
-        setFeature(
-          fType.create( FeatureUtil.getDefaultAttributeValues(fType) )
-        );
-      else
-        setFeature( (Feature)null );
-
-    } catch (Exception err) {
-      throw new RuntimeException(err);
-    }
-  }
-
-  /**
-   * Liefert den {@link FeatureType}, der in der Tabelle dargestellt wird.
-   */
-  public FeatureType getFeatureType() {
-    return this.featureType;
-  }
-
-  /**
-   * Liefert das {@link Feature}, das in der Tabelle dargestellt wird.
-   */
-  public Feature getFeature() {
-    return this.feature;
-  }
-
-  /**
-   * Liefert die Spaltennamen der Tabelle.
-   */
-  public String[] createColumnNames() {
-    return new String[] {
-        GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.feature.FeatureTableModel.AttrName"),
-        GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.feature.FeatureTableModel.AttrType"),
-        GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.feature.FeatureTableModel.AttrValue")
-    };
-  }
-
-
-  /**
-   * Liefert die Anzahl an Zeilen. Diese entspricht der Anzahl an Attributen
-   * des {@link Feature}.
-   */
-  public int getRowCount() {
-    return featureType != null ? featureType.getAttributeCount() : 0;
-  }
-
-  /**
-   * Liefert einen Wert der Tabelle.
-   * @param rowIndex  Zeilen-Index (beginnend bei 0)
-   * @param columnIndex Spalten-Index (beginnend bei 0)
-   */
-  public Object getValueAt(int rowIndex, int columnIndex) {
-    AttributeType aType = featureType.getAttributeType(rowIndex);
-    switch ( columnIndex ) {
-      case 0: return aType.getLocalName();
-      case 1: return aType.getBinding().getSimpleName();
-      case 2: return feature.getAttribute(rowIndex);
-    }
-    return null;
-  }
-
-  /**
-   * Setzt einen Wert der Tabelle. Nur fuer Spalte "Wert" (2) relevant.
-   * @param rowIndex  Zeilen-Index (beginnend bei 0)
-   * @param columnIndex Spalten-Index (beginnend bei 0)
-   */
-  @Override
-  public void setValueAt(Object value, int rowIndex, int columnIndex) {
-    AttributeType aType = featureType.getAttributeType(rowIndex);
-    if ( "".equals(value) )
-      value = null;
-    if ( value != null &&  Number.class.isAssignableFrom(aType.getBinding()) )
-      value = BaseTypeUtil.convertFromString(value.toString(), aType.getBinding());
-    if ( value == null && !aType.isNillable() )
-      value = FeatureUtil.getDefaultAttributeValue(aType.getBinding());
-
-    try {
-      switch ( columnIndex ) {
-        case 2: feature.setAttribute(rowIndex, value);
-      }
-    } catch (Exception err) {
-      throw new RuntimeException(err);
-    }
-  }
-
-  /**
-   * Liefert {@code true} nur fuer die Spalte "Wert" (2) und nur
-   * dann, wenn es sich um eine numerisches oder String-Attribut
-   * handelt.
-   */
-  @Override
-  public boolean isCellEditable(int rowIndex, int columnIndex) {
-    Class aClass = featureType.getAttributeType(rowIndex).getBinding();
-    return columnIndex == 2 && BaseTypeUtil.isBaseType( aClass );
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.feature;
+
+import javax.swing.table.TableModel;
+
+import org.geotools.feature.AttributeType;
+import org.geotools.feature.Feature;
+import org.geotools.feature.FeatureType;
+
+import schmitzm.geotools.gui.GeotoolsGUIUtil;
+import schmitzm.swing.table.AbstractTableModel;
+import schmitzm.temp.BaseTypeUtil;
+
+/**
+ * Diese Klasse stellt ein {@link TableModel} auf einem einzelnen {@link Feature}
+ * dar. Dieses definiert drei Spalten:
+ * <ol>
+ *   <li>Attribut-Name</li>
+ *   <li>Attribut-Typ</li>
+ *   <li>Wert des Attributs als Text-Eingabe</li>
+ * </ol>
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class FeatureTableModel extends AbstractTableModel {
+  /** {@link Feature} das in der Tabelle dargestellt wird. */
+  protected Feature feature = null;
+  /** {@link FeatureType} der in der Tabelle dargestellt wird. */
+  protected FeatureType featureType = null;
+
+  /**
+   * Erstellt ein leeres Tabellen-Modell.
+   */
+  public FeatureTableModel() {
+    this((Feature)null);
+  }
+
+  /**
+   * Erstellt ein neues Tabellen-Modell.
+   * @param feature dargestelltes Feature
+   */
+  public FeatureTableModel(Feature feature) {
+    this( feature != null ? feature.getFeatureType() : null);
+    setFeature( feature );
+  }
+
+  /**
+   * Erstellt ein neues Tabellen-Modell.
+   * @param type ein FeatureType
+   */
+  public FeatureTableModel(FeatureType type) {
+    super();
+    setFeature( type );
+  }
+
+  /**
+   * Setzt das {@link Feature}, das in der Tabelle dargestellt wird.
+   * @param feature {@link Feature}
+   */
+  public void setFeature(Feature feature) {
+    this.feature     = feature;
+    this.featureType = feature != null ? feature.getFeatureType() : null;
+    this.fireTableDataChanged();
+  }
+
+  /**
+   * Setzt das {@link Feature}, das in der Tabelle dargestellt wird.
+   * @param fType {@link FeatureType} fuer den eine Standard-Feature
+   *              angezeigt wird
+   */
+  public void setFeature(FeatureType fType) {
+    try {
+      if ( fType != null )
+        setFeature(
+          fType.create( FeatureUtil.getDefaultAttributeValues(fType) )
+        );
+      else
+        setFeature( (Feature)null );
+
+    } catch (Exception err) {
+      throw new RuntimeException(err);
+    }
+  }
+
+  /**
+   * Liefert den {@link FeatureType}, der in der Tabelle dargestellt wird.
+   */
+  public FeatureType getFeatureType() {
+    return this.featureType;
+  }
+
+  /**
+   * Liefert das {@link Feature}, das in der Tabelle dargestellt wird.
+   */
+  public Feature getFeature() {
+    return this.feature;
+  }
+
+  /**
+   * Liefert die Spaltennamen der Tabelle.
+   */
+  public String[] createColumnNames() {
+    return new String[] {
+        GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.feature.FeatureTableModel.AttrName"),
+        GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.feature.FeatureTableModel.AttrType"),
+        GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.feature.FeatureTableModel.AttrValue")
+    };
+  }
+
+
+  /**
+   * Liefert die Anzahl an Zeilen. Diese entspricht der Anzahl an Attributen
+   * des {@link Feature}.
+   */
+  public int getRowCount() {
+    return featureType != null ? featureType.getAttributeCount() : 0;
+  }
+
+  /**
+   * Liefert einen Wert der Tabelle.
+   * @param rowIndex  Zeilen-Index (beginnend bei 0)
+   * @param columnIndex Spalten-Index (beginnend bei 0)
+   */
+  public Object getValueAt(int rowIndex, int columnIndex) {
+    AttributeType aType = featureType.getAttributeType(rowIndex);
+    switch ( columnIndex ) {
+      case 0: return aType.getLocalName();
+      case 1: return aType.getBinding().getSimpleName();
+      case 2: return feature.getAttribute(rowIndex);
+    }
+    return null;
+  }
+
+  /**
+   * Setzt einen Wert der Tabelle. Nur fuer Spalte "Wert" (2) relevant.
+   * @param rowIndex  Zeilen-Index (beginnend bei 0)
+   * @param columnIndex Spalten-Index (beginnend bei 0)
+   */
+  @Override
+  public void setValueAt(Object value, int rowIndex, int columnIndex) {
+    AttributeType aType = featureType.getAttributeType(rowIndex);
+    if ( "".equals(value) )
+      value = null;
+    if ( value != null &&  Number.class.isAssignableFrom(aType.getBinding()) )
+      value = BaseTypeUtil.convertFromString(value.toString(), aType.getBinding());
+    if ( value == null && !aType.isNillable() )
+      value = FeatureUtil.getDefaultAttributeValue(aType.getBinding());
+
+    try {
+      switch ( columnIndex ) {
+        case 2: feature.setAttribute(rowIndex, value);
+      }
+    } catch (Exception err) {
+      throw new RuntimeException(err);
+    }
+  }
+
+  /**
+   * Liefert {@code true} nur fuer die Spalte "Wert" (2) und nur
+   * dann, wenn es sich um eine numerisches oder String-Attribut
+   * handelt.
+   */
+  @Override
+  public boolean isCellEditable(int rowIndex, int columnIndex) {
+    Class aClass = featureType.getAttributeType(rowIndex).getBinding();
+    return columnIndex == 2 && BaseTypeUtil.isBaseType( aClass );
+  }
+
+}

Modified: trunk/src/schmitzm/geotools/feature/FeatureTypeBuilderTableModel.java
===================================================================
--- trunk/src/schmitzm/geotools/feature/FeatureTypeBuilderTableModel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/feature/FeatureTypeBuilderTableModel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,387 +1,406 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.geotools.feature;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.util.Vector;
-
-import javax.swing.CellEditor;
-import javax.swing.DefaultCellEditor;
-import javax.swing.JCheckBox;
-import javax.swing.JComboBox;
-import javax.swing.JTable;
-import javax.swing.JTextField;
-import javax.swing.table.TableModel;
-
-import org.geotools.feature.AttributeType;
-import org.geotools.feature.AttributeTypeFactory;
-import org.geotools.feature.DefaultAttributeType;
-import org.geotools.feature.FeatureType;
-import org.geotools.feature.FeatureTypeBuilder;
-import org.geotools.feature.SchemaException;
-import org.geotools.feature.type.GeometricAttributeType;
-import org.geotools.gui.swing.referencing.CoordinateTableModel.CellRenderer;
-
-import schmitzm.geotools.gui.GeotoolsGUIUtil;
-import schmitzm.swing.BooleanInputOption;
-import schmitzm.swing.ManualInputOption;
-import schmitzm.swing.SelectionInputOption;
-import schmitzm.swing.table.AbstractMutableTableModel;
-import schmitzm.swing.table.ComponentRenderer;
-import schmitzm.temp.BaseTypeUtil;
-
-import com.vividsolutions.jts.geom.LineString;
-import com.vividsolutions.jts.geom.Point;
-import com.vividsolutions.jts.geom.Polygon;
-
-/**
- * Diese Klasse stellt ein {@link TableModel} auf einem "unfertigen" {@link FeatureType}
- * dar. Dieses definiert vier Spalten:
- * <ol>
- *   <li>Attribut-Name als Text-Eingabe</li>
- *   <li>Attribut-Typ als Auswahl-Feld</li>
- *   <li>"Nillable"-Eigenschaft als Check-Box</li>
- *   <li>"AutoValue"-Eigenschaft als Check-Box</li>
- *   <li>Standard-Wert als Text-Eingabe</li>
- * </ol>
- * Da das {@link TableModel} auf einem {@link FeatureTypeBuilder} basiert,
- * bietet es die Moeglichkeit, Attribute hinzuzufuegen oder zu loeschen.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class FeatureTypeBuilderTableModel extends AbstractMutableTableModel {
-  /** Zur Verfuegung stehende Attribut-Typen. */
-  public static final Class[] ATTR_TYPES = new Class[] {
-    String.class,
-    Integer.class,
-    Long.class,
-    Byte.class,
-    Boolean.class,
-    Double.class,
-    Float.class,
-    BigInteger.class,
-    BigDecimal.class,
-    Point.class,
-    LineString.class,
-    Polygon.class
-  };
-
-  public static final String[] ATTR_TYPES_DESC = new String[ATTR_TYPES.length];
-  static {
-    for (int i=0; i<ATTR_TYPES_DESC.length; i++)
-      ATTR_TYPES_DESC[i] = ATTR_TYPES[i].getSimpleName();
-  }
-
-
-  /** Die in der Tabelle dargestellten Attribute. */
-  protected Vector<AttributeDefinition> attrDefinitions = new Vector<AttributeDefinition>();
-
-  /** {@link FeatureTypeBuilder} der in der Tabelle dargestellt wird. */
-  protected FeatureTypeBuilder featureTypeBuilder = null;
-
-  /**
-   * Erstellt ein leeres Tabellen-Modell.
-   */
-  public FeatureTypeBuilderTableModel() {
-    this((FeatureTypeBuilder)null);
-  }
-
-  /**
-   * Erstellt ein neues Tabellen-Modell.
-   * @param type ein FeatureType, der editiert wird
-   */
-  public FeatureTypeBuilderTableModel(FeatureType type) {
-    super();
-    setFeatureType(type);
-  }
-
-  /**
-   * Erstellt ein neues Tabellen-Modell.
-   * @param type ein FeatureType, der editiert wird
-   */
-  public FeatureTypeBuilderTableModel(FeatureTypeBuilder builder) {
-    super();
-    setFeatureTypeBuilder(builder);
-  }
-
-  /**
-   * Liefert die Spaltennamen der Tabelle.
-   */
-  public String[] createColumnNames() {
-    return new String[] {
-        GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.gui.FeatureTypeBuilderTableModel.AttrName"),
-        GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.gui.FeatureTypeBuilderTableModel.AttrType"),
-        GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.gui.FeatureTypeBuilderTableModel.Nillable"),
-        GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.gui.FeatureTypeBuilderTableModel.AutoValue"),
-        GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.gui.FeatureTypeBuilderTableModel.DefValue")
-    };
-  }
-
-  /**
-   * Setzt {@link CellRenderer} und {@link CellEditor} fuer die Tabelle, sowie
-   * eine adaequate Zeilen-Hoehe.
-   */
-  @Override
-  public void initTable(JTable table) {
-    table.setRowHeight( new JComboBox(new String[] {"Dummy"}).getPreferredSize().height );
-    table.getColumnModel().getColumn(0).setCellRenderer( new ComponentRenderer.JTextField() );
-    table.getColumnModel().getColumn(1).setCellRenderer( new ComponentRenderer.JComboBox() );
-    table.getColumnModel().getColumn(2).setCellRenderer( new ComponentRenderer.JCheckBox() );
-    table.getColumnModel().getColumn(3).setCellRenderer( new ComponentRenderer.JCheckBox() );
-    table.getColumnModel().getColumn(4).setCellRenderer( new ComponentRenderer.JTextField() );
-    table.getColumnModel().getColumn(0).setCellEditor( new DefaultCellEditor( new JTextField() ) );
-    table.getColumnModel().getColumn(1).setCellEditor( new DefaultCellEditor( new JComboBox( ATTR_TYPES_DESC ) ) );
-    table.getColumnModel().getColumn(2).setCellEditor( new DefaultCellEditor( new JCheckBox() {
-      public int getHorizontalAlignment() {
-        return this.CENTER;
-      }
-      public int getVerticalAlignment() {
-        return this.CENTER;
-      }
-    }));
-    table.getColumnModel().getColumn(3).setCellEditor( new DefaultCellEditor( new JCheckBox() {
-      public int getHorizontalAlignment() {
-        return this.CENTER;
-      }
-      public int getVerticalAlignment() {
-        return this.CENTER;
-      }
-    }));
-    table.getColumnModel().getColumn(4).setCellEditor( new DefaultCellEditor( new JTextField() ) );
-  }
-
-  /**
-   * Liefert die Anzahl an Attributen in der Tabelle.
-   */
-  public int getRowCount() {
-    return attrDefinitions.size();
-  }
-
-  /**
-   * Setzt den {@link FeatureTypeBuilder}, der in der Tabelle dargestellt wird.
-   * @param builder {@link FeatureTypeBuilder}
-   */
-  public void setFeatureTypeBuilder(FeatureTypeBuilder builder) {
-    if ( builder == null )
-      builder = FeatureTypeBuilder.newInstance("New Type");
-
-    this.featureTypeBuilder = builder;
-    // Attribut-Typen in Array speichern
-    attrDefinitions.clear();
-    if ( featureTypeBuilder != null )
-      for (int i=0; i<featureTypeBuilder.getAttributeCount(); i++) {
-        AttributeType type = featureTypeBuilder.get(i);
-        attrDefinitions.add( new AttributeDefinition(
-            type.getLocalName(),
-            type.getBinding(),
-            type.isNillable(),
-            false,
-            type.createDefaultValue()
-        ) );
-      }
-    this.fireTableDataChanged();
-  }
-
-  /**
-   * Setzt den {@link FeatureTypeBuilder}, der in der Tabelle dargestellt wird.
-   * Dieser wird mit den Attributen des angegebenen {@link FeatureType}
-   * initialisiert
-   * @param ftype {@link FeatureType}
-   */
-  public void setFeatureType(FeatureType ftype) {
-    if ( ftype != null ) {
-      FeatureTypeBuilder builder = FeatureTypeBuilder.newInstance(ftype.getTypeName());
-      builder.addTypes(ftype.getAttributeTypes());
-      setFeatureTypeBuilder(builder);
-    } else
-      setFeatureTypeBuilder(null);
-  }
-
-  /**
-   * Erzeugt einen neuen {@link FeatureType}, aus den in der Tabelle dargestellen
-   * Attributen.
-   */
-  public FeatureType createFeatureType() {
-    try {
-//      this.featureTypeBuilder.removeAll(); // does not work because of BUG in gt2-2.4.4
-      for (;featureTypeBuilder.getAttributeCount() >0;)
-        this.featureTypeBuilder.removeType(0);
-
-      for (AttributeDefinition aDef : attrDefinitions) {
-        AttributeType aType = aDef.createAttributeType();
-        featureTypeBuilder.addType( aType );
-        if ( featureTypeBuilder.getDefaultGeometry() == null &&
-             aType instanceof GeometricAttributeType )
-          featureTypeBuilder.setDefaultGeometry( (GeometricAttributeType)aType );
-      }
-      return this.featureTypeBuilder.getFeatureType();
-    } catch (SchemaException err) {
-      throw new RuntimeException(err);
-    }
-  }
-
-  /**
-   * Prueft, ob eine Tabellen-Zelle editierbar ist.
-   * @return {@code true} fuer jede Zelle
-   */
-  public boolean isCellEditable(int rowIndex, int columnIndex) {
-    return true;
-  }
-
-  /**
-   * Liefert einen Wert der Tabelle.
-   * @param rowIndex  Zeilen-Index (beginnend bei 0)
-   * @param columnIndex Spalten-Index (beginnend bei 0)
-   */
-  public Object getValueAt(int rowIndex, int columnIndex) {
-    AttributeDefinition aDef = attrDefinitions.elementAt(rowIndex);
-    switch ( columnIndex ) {
-      case 0: return aDef.name.getValue();
-      case 1: return aDef.type.getSelectedDisplayItem();
-      case 2: return aDef.nillable.getValue();
-      case 3: return aDef.autoValue.getValue();
-      case 4: return aDef.defaultValue.getValue();
-    }
-    return null;
-  }
-
-  /**
-   * Setzt einen Wert der Tabelle.
-   * @param value neuer Wert
-   * @param rowIndex  Zeilen-Index (beginnend bei 0)
-   * @param columnIndex Spalten-Index (beginnend bei 0)
-   */
-  public void setValueAt(Object value, int rowIndex, int columnIndex) {
-    AttributeDefinition aDef = attrDefinitions.elementAt(rowIndex);
-    switch ( columnIndex ) {
-      case 0: aDef.name.setValue(value); break;
-      case 1: aDef.type.setSelectedDisplayItem(value); break;
-      case 2: aDef.nillable.setValue(value); break;
-      case 3: aDef.autoValue.setValue(value); break;
-      case 4: aDef.defaultValue.setValue(value); break;
-    }
-  }
-
-  /**
-   * Fuegt der Tabelle ein neues Standard-Attribut hinzu.
-   */
-  public void performAddRow() {
-    AttributeDefinition newAttrDef = new AttributeDefinition();
-    newAttrDef.name.setValue( GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.gui.FeatureTypeBuilderTableModel.NewAttr",getRowCount() ) );
-    attrDefinitions.add( newAttrDef );
-    fireTableDataChanged();
-  }
-
-  /**
-   * Macht nichts.
-   */
-  public void performChangeData(int row, int col) {
-    // does nothing
-  }
-
-  /**
-   * Entfernt ein Attribut aus der Tabelle.
-   */
-  public void performRemoveRow(int row) {
-    attrDefinitions.removeElementAt(row);
-    fireTableDataChanged();
-  }
-
-  /**
-   * Defines an Attribute displayed in the table. The advantage of this helper
-   * class is that it does <b>not</b> check the consistency of the inputs
-   * immediately on the input! This is importend richtig
-   *
-   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-   *
-   */
-  protected class AttributeDefinition {
-    /** Manual input field for the attribute name. */
-    protected ManualInputOption.Text name;
-    /** Choice input field for the attribute type.
-     *  @see FeatureTypeBuilderTableModel.ATTR_TYPES */
-    protected SelectionInputOption.Combo<Class> type = null;
-    /** Manual input field for the attribute's default value. */
-    protected ManualInputOption.Text defaultValue;
-    /** Checkbox for the attribute's nillable property. */
-    protected BooleanInputOption nillable = null;
-    /** Checkbox to indicate that the attribute value is generated
-     *  automatically. */
-    protected BooleanInputOption autoValue = null;
-
-    /**
-     * Creates an empty attribute definition.
-     */
-    public AttributeDefinition() {
-      name         = new ManualInputOption.Text(null, true); // Attribute name is mandatory
-      type         = new SelectionInputOption.Combo<Class>(null,true,ATTR_TYPES,0,ATTR_TYPES_DESC);
-      defaultValue = new ManualInputOption.Text(null,false); // Default value is not mandatory
-      nillable     = new BooleanInputOption(null,true);
-      autoValue    = new BooleanInputOption(null,false);
-    }
-
-    /**
-     * Creates a new attribute definition. The consistency of the inputs (e.g. type and default
-     * value) is not checked before {@link #createAttributeType()} is called.
-     * @param name name of the attribute
-     * @param type value type of the attribute
-     * @param nillable indicates whether the attribute is mandatory
-     * @param defaultValue default value for the attribute
-     */
-    public AttributeDefinition(String name, Class type, boolean nillable, boolean autoValue, Object defaultValue) {
-      this();
-      this.name.setValue(name);
-      this.type.setValue(type);
-      this.nillable.setValue(nillable);
-      this.autoValue.setValue(autoValue);
-      this.defaultValue.setValue(defaultValue);
-    }
-
-    /**
-     * Creates an {@link AttributeType} from the definition.
-     * @return {@link DefaultAttributeType} or {@link GeometricAttributeType}
-     */
-    public AttributeType createAttributeType() {
-      Class   type         = (Class)this.type.getValue();
-      boolean nillable     = (Boolean)this.nillable.getValue();
-      Object  defaultValue = this.defaultValue.getValue();
-      if ( "".equals(defaultValue) )
-        defaultValue = null;
-      if ( defaultValue != null &&  Number.class.isAssignableFrom(type) )
-        defaultValue = BaseTypeUtil.convertFromString(defaultValue.toString(), type);
-      if ( defaultValue == null && !nillable )
-        defaultValue = FeatureUtil.getDefaultAttributeValue(type);
-
-      AttributeType aType = AttributeTypeFactory.newAttributeType(
-          (String)name.getValue(),
-          type,
-          nillable,
-          null,
-          defaultValue,
-          null
-      );
-
-      AutoValueGenerator valueGenerator = null;
-      if ( autoValue.getValue() ) {
-        if ( Number.class.isAssignableFrom(type) )
-          valueGenerator = new NumberValueGenerator((Number)defaultValue);
-        else
-          throw new UnsupportedOperationException( GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.gui.JEditorToolBar.NewLayer.Err.AutoVal", type.getSimpleName()));
-        FeatureUtil.registerAutoValueGenerator(aType, valueGenerator);
-      } else
-        FeatureUtil.unregisterAutoValueGenerator(aType);
-
-
-      return aType;
-    }
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.feature;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Vector;
+
+import javax.swing.CellEditor;
+import javax.swing.DefaultCellEditor;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JTable;
+import javax.swing.JTextField;
+import javax.swing.table.TableModel;
+
+import org.geotools.feature.AttributeType;
+import org.geotools.feature.AttributeTypeFactory;
+import org.geotools.feature.DefaultAttributeType;
+import org.geotools.feature.FeatureType;
+import org.geotools.feature.FeatureTypeBuilder;
+import org.geotools.feature.SchemaException;
+import org.geotools.feature.type.GeometricAttributeType;
+import org.geotools.gui.swing.referencing.CoordinateTableModel.CellRenderer;
+
+import schmitzm.geotools.gui.GeotoolsGUIUtil;
+import schmitzm.swing.BooleanInputOption;
+import schmitzm.swing.ManualInputOption;
+import schmitzm.swing.SelectionInputOption;
+import schmitzm.swing.table.AbstractMutableTableModel;
+import schmitzm.swing.table.ComponentRenderer;
+import schmitzm.temp.BaseTypeUtil;
+
+import com.vividsolutions.jts.geom.LineString;
+import com.vividsolutions.jts.geom.Point;
+import com.vividsolutions.jts.geom.Polygon;
+
+/**
+ * Diese Klasse stellt ein {@link TableModel} auf einem "unfertigen" {@link FeatureType}
+ * dar. Dieses definiert vier Spalten:
+ * <ol>
+ *   <li>Attribut-Name als Text-Eingabe</li>
+ *   <li>Attribut-Typ als Auswahl-Feld</li>
+ *   <li>"Nillable"-Eigenschaft als Check-Box</li>
+ *   <li>"AutoValue"-Eigenschaft als Check-Box</li>
+ *   <li>Standard-Wert als Text-Eingabe</li>
+ * </ol>
+ * Da das {@link TableModel} auf einem {@link FeatureTypeBuilder} basiert,
+ * bietet es die Moeglichkeit, Attribute hinzuzufuegen oder zu loeschen.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class FeatureTypeBuilderTableModel extends AbstractMutableTableModel {
+  /** Zur Verfuegung stehende Attribut-Typen. */
+  public static final Class[] ATTR_TYPES = new Class[] {
+    String.class,
+    Integer.class,
+    Long.class,
+    Byte.class,
+    Boolean.class,
+    Double.class,
+    Float.class,
+    BigInteger.class,
+    BigDecimal.class,
+    Point.class,
+    LineString.class,
+    Polygon.class
+  };
+
+  public static final String[] ATTR_TYPES_DESC = new String[ATTR_TYPES.length];
+  static {
+    for (int i=0; i<ATTR_TYPES_DESC.length; i++)
+      ATTR_TYPES_DESC[i] = ATTR_TYPES[i].getSimpleName();
+  }
+
+
+  /** Die in der Tabelle dargestellten Attribute. */
+  protected Vector<AttributeDefinition> attrDefinitions = new Vector<AttributeDefinition>();
+
+  /** {@link FeatureTypeBuilder} der in der Tabelle dargestellt wird. */
+  protected FeatureTypeBuilder featureTypeBuilder = null;
+
+  /**
+   * Erstellt ein leeres Tabellen-Modell.
+   */
+  public FeatureTypeBuilderTableModel() {
+    this((FeatureTypeBuilder)null);
+  }
+
+  /**
+   * Erstellt ein neues Tabellen-Modell.
+   * @param type ein FeatureType, der editiert wird
+   */
+  public FeatureTypeBuilderTableModel(FeatureType type) {
+    super();
+    setFeatureType(type);
+  }
+
+  /**
+   * Erstellt ein neues Tabellen-Modell.
+   * @param type ein FeatureType, der editiert wird
+   */
+  public FeatureTypeBuilderTableModel(FeatureTypeBuilder builder) {
+    super();
+    setFeatureTypeBuilder(builder);
+  }
+
+  /**
+   * Liefert die Spaltennamen der Tabelle.
+   */
+  public String[] createColumnNames() {
+    return new String[] {
+        GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.gui.FeatureTypeBuilderTableModel.AttrName"),
+        GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.gui.FeatureTypeBuilderTableModel.AttrType"),
+        GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.gui.FeatureTypeBuilderTableModel.Nillable"),
+        GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.gui.FeatureTypeBuilderTableModel.AutoValue"),
+        GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.gui.FeatureTypeBuilderTableModel.DefValue")
+    };
+  }
+
+  /**
+   * Setzt {@link CellRenderer} und {@link CellEditor} fuer die Tabelle, sowie
+   * eine adaequate Zeilen-Hoehe.
+   */
+  @Override
+  public void initTable(JTable table) {
+    table.setRowHeight( new JComboBox(new String[] {"Dummy"}).getPreferredSize().height );
+    table.getColumnModel().getColumn(0).setCellRenderer( new ComponentRenderer.JTextField() );
+    table.getColumnModel().getColumn(1).setCellRenderer( new ComponentRenderer.JComboBox() );
+    table.getColumnModel().getColumn(2).setCellRenderer( new ComponentRenderer.JCheckBox() );
+    table.getColumnModel().getColumn(3).setCellRenderer( new ComponentRenderer.JCheckBox() );
+    table.getColumnModel().getColumn(4).setCellRenderer( new ComponentRenderer.JTextField() );
+    table.getColumnModel().getColumn(0).setCellEditor( new DefaultCellEditor( new JTextField() ) );
+    table.getColumnModel().getColumn(1).setCellEditor( new DefaultCellEditor( new JComboBox( ATTR_TYPES_DESC ) ) );
+    table.getColumnModel().getColumn(2).setCellEditor( new DefaultCellEditor( new JCheckBox() {
+      public int getHorizontalAlignment() {
+        return this.CENTER;
+      }
+      public int getVerticalAlignment() {
+        return this.CENTER;
+      }
+    }));
+    table.getColumnModel().getColumn(3).setCellEditor( new DefaultCellEditor( new JCheckBox() {
+      public int getHorizontalAlignment() {
+        return this.CENTER;
+      }
+      public int getVerticalAlignment() {
+        return this.CENTER;
+      }
+    }));
+    table.getColumnModel().getColumn(4).setCellEditor( new DefaultCellEditor( new JTextField() ) );
+  }
+
+  /**
+   * Liefert die Anzahl an Attributen in der Tabelle.
+   */
+  public int getRowCount() {
+    return attrDefinitions.size();
+  }
+
+  /**
+   * Setzt den {@link FeatureTypeBuilder}, der in der Tabelle dargestellt wird.
+   * @param builder {@link FeatureTypeBuilder}
+   */
+  public void setFeatureTypeBuilder(FeatureTypeBuilder builder) {
+    if ( builder == null )
+      builder = FeatureTypeBuilder.newInstance("New Type");
+
+    this.featureTypeBuilder = builder;
+    // Attribut-Typen in Array speichern
+    attrDefinitions.clear();
+    if ( featureTypeBuilder != null )
+      for (int i=0; i<featureTypeBuilder.getAttributeCount(); i++) {
+        AttributeType type = featureTypeBuilder.get(i);
+        attrDefinitions.add( new AttributeDefinition(
+            type.getLocalName(),
+            type.getBinding(),
+            type.isNillable(),
+            false,
+            type.createDefaultValue()
+        ) );
+      }
+    this.fireTableDataChanged();
+  }
+
+  /**
+   * Setzt den {@link FeatureTypeBuilder}, der in der Tabelle dargestellt wird.
+   * Dieser wird mit den Attributen des angegebenen {@link FeatureType}
+   * initialisiert
+   * @param ftype {@link FeatureType}
+   */
+  public void setFeatureType(FeatureType ftype) {
+    if ( ftype != null ) {
+      FeatureTypeBuilder builder = FeatureTypeBuilder.newInstance(ftype.getTypeName());
+      builder.addTypes(ftype.getAttributeTypes());
+      setFeatureTypeBuilder(builder);
+    } else
+      setFeatureTypeBuilder(null);
+  }
+
+  /**
+   * Erzeugt einen neuen {@link FeatureType}, aus den in der Tabelle dargestellen
+   * Attributen.
+   */
+  public FeatureType createFeatureType() {
+    try {
+//      this.featureTypeBuilder.removeAll(); // does not work because of BUG in gt2-2.4.4
+      for (;featureTypeBuilder.getAttributeCount() >0;)
+        this.featureTypeBuilder.removeType(0);
+
+      for (AttributeDefinition aDef : attrDefinitions) {
+        AttributeType aType = aDef.createAttributeType();
+        featureTypeBuilder.addType( aType );
+        if ( featureTypeBuilder.getDefaultGeometry() == null &&
+             aType instanceof GeometricAttributeType )
+          featureTypeBuilder.setDefaultGeometry( (GeometricAttributeType)aType );
+      }
+      return this.featureTypeBuilder.getFeatureType();
+    } catch (SchemaException err) {
+      throw new RuntimeException(err);
+    }
+  }
+
+  /**
+   * Prueft, ob eine Tabellen-Zelle editierbar ist.
+   * @return {@code true} fuer jede Zelle
+   */
+  public boolean isCellEditable(int rowIndex, int columnIndex) {
+    return true;
+  }
+
+  /**
+   * Liefert einen Wert der Tabelle.
+   * @param rowIndex  Zeilen-Index (beginnend bei 0)
+   * @param columnIndex Spalten-Index (beginnend bei 0)
+   */
+  public Object getValueAt(int rowIndex, int columnIndex) {
+    AttributeDefinition aDef = attrDefinitions.elementAt(rowIndex);
+    switch ( columnIndex ) {
+      case 0: return aDef.name.getValue();
+      case 1: return aDef.type.getSelectedDisplayItem();
+      case 2: return aDef.nillable.getValue();
+      case 3: return aDef.autoValue.getValue();
+      case 4: return aDef.defaultValue.getValue();
+    }
+    return null;
+  }
+
+  /**
+   * Setzt einen Wert der Tabelle.
+   * @param value neuer Wert
+   * @param rowIndex  Zeilen-Index (beginnend bei 0)
+   * @param columnIndex Spalten-Index (beginnend bei 0)
+   */
+  public void setValueAt(Object value, int rowIndex, int columnIndex) {
+    AttributeDefinition aDef = attrDefinitions.elementAt(rowIndex);
+    switch ( columnIndex ) {
+      case 0: aDef.name.setValue(value); break;
+      case 1: aDef.type.setSelectedDisplayItem(value); break;
+      case 2: aDef.nillable.setValue(value); break;
+      case 3: aDef.autoValue.setValue(value); break;
+      case 4: aDef.defaultValue.setValue(value); break;
+    }
+  }
+
+  /**
+   * Fuegt der Tabelle ein neues Standard-Attribut hinzu.
+   */
+  public void performAddRow() {
+    AttributeDefinition newAttrDef = new AttributeDefinition();
+    newAttrDef.name.setValue( GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.gui.FeatureTypeBuilderTableModel.NewAttr",getRowCount() ) );
+    attrDefinitions.add( newAttrDef );
+    fireTableDataChanged();
+  }
+
+  /**
+   * Macht nichts.
+   */
+  public void performChangeData(int row, int col) {
+    // does nothing
+  }
+
+  /**
+   * Entfernt ein Attribut aus der Tabelle.
+   */
+  public void performRemoveRow(int row) {
+    attrDefinitions.removeElementAt(row);
+    fireTableDataChanged();
+  }
+
+  /**
+   * Defines an Attribute displayed in the table. The advantage of this helper
+   * class is that it does <b>not</b> check the consistency of the inputs
+   * immediately on the input! This is importend richtig
+   *
+   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+   *
+   */
+  protected class AttributeDefinition {
+    /** Manual input field for the attribute name. */
+    protected ManualInputOption.Text name;
+    /** Choice input field for the attribute type.
+     *  @see FeatureTypeBuilderTableModel.ATTR_TYPES */
+    protected SelectionInputOption.Combo<Class> type = null;
+    /** Manual input field for the attribute's default value. */
+    protected ManualInputOption.Text defaultValue;
+    /** Checkbox for the attribute's nillable property. */
+    protected BooleanInputOption nillable = null;
+    /** Checkbox to indicate that the attribute value is generated
+     *  automatically. */
+    protected BooleanInputOption autoValue = null;
+
+    /**
+     * Creates an empty attribute definition.
+     */
+    public AttributeDefinition() {
+      name         = new ManualInputOption.Text(null, true); // Attribute name is mandatory
+      type         = new SelectionInputOption.Combo<Class>(null,true,ATTR_TYPES,0,ATTR_TYPES_DESC);
+      defaultValue = new ManualInputOption.Text(null,false); // Default value is not mandatory
+      nillable     = new BooleanInputOption(null,true);
+      autoValue    = new BooleanInputOption(null,false);
+    }
+
+    /**
+     * Creates a new attribute definition. The consistency of the inputs (e.g. type and default
+     * value) is not checked before {@link #createAttributeType()} is called.
+     * @param name name of the attribute
+     * @param type value type of the attribute
+     * @param nillable indicates whether the attribute is mandatory
+     * @param defaultValue default value for the attribute
+     */
+    public AttributeDefinition(String name, Class type, boolean nillable, boolean autoValue, Object defaultValue) {
+      this();
+      this.name.setValue(name);
+      this.type.setValue(type);
+      this.nillable.setValue(nillable);
+      this.autoValue.setValue(autoValue);
+      this.defaultValue.setValue(defaultValue);
+    }
+
+    /**
+     * Creates an {@link AttributeType} from the definition.
+     * @return {@link DefaultAttributeType} or {@link GeometricAttributeType}
+     */
+    public AttributeType createAttributeType() {
+      Class   type         = (Class)this.type.getValue();
+      boolean nillable     = (Boolean)this.nillable.getValue();
+      Object  defaultValue = this.defaultValue.getValue();
+      if ( "".equals(defaultValue) )
+        defaultValue = null;
+      if ( defaultValue != null &&  Number.class.isAssignableFrom(type) )
+        defaultValue = BaseTypeUtil.convertFromString(defaultValue.toString(), type);
+      if ( defaultValue == null && !nillable )
+        defaultValue = FeatureUtil.getDefaultAttributeValue(type);
+
+      AttributeType aType = AttributeTypeFactory.newAttributeType(
+          (String)name.getValue(),
+          type,
+          nillable,
+          null,
+          defaultValue,
+          null
+      );
+
+      AutoValueGenerator valueGenerator = null;
+      if ( autoValue.getValue() ) {
+        if ( Number.class.isAssignableFrom(type) )
+          valueGenerator = new NumberValueGenerator((Number)defaultValue);
+        else
+          throw new UnsupportedOperationException( GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.gui.JEditorToolBar.NewLayer.Err.AutoVal", type.getSimpleName()));
+        FeatureUtil.registerAutoValueGenerator(aType, valueGenerator);
+      } else
+        FeatureUtil.unregisterAutoValueGenerator(aType);
+
+
+      return aType;
+    }
+  }
+}

Modified: trunk/src/schmitzm/geotools/feature/FeatureTypeTableModel.java
===================================================================
--- trunk/src/schmitzm/geotools/feature/FeatureTypeTableModel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/feature/FeatureTypeTableModel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,131 +1,150 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.geotools.feature;
-
-import java.util.Vector;
-
-import javax.swing.table.TableModel;
-
-import org.geotools.feature.AttributeType;
-import org.geotools.feature.FeatureType;
-
-import schmitzm.geotools.gui.GeotoolsGUIUtil;
-import schmitzm.swing.table.AbstractTableModel;
-
-
-/**
- * Diese Klasse stellt ein {@link TableModel} auf einem {@link FeatureType}
- * dar. Dieses definiert zwei Spalten, in denen der Name (0) und der
- * Typ (1) der Attribute dargestellt werden.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class FeatureTypeTableModel extends AbstractTableModel {
-  /** {@link FeatureType} das in der Tabelle dargestellt wird. */
-  protected FeatureType featureType = null;
-  /** Bestimmt die angezeigten Features */
-  protected AttributeTypeFilter attrFilter = AttributeTypeFilter.ALL;
-
-  /** Speichert die (die gefilterten!) Attibut-Typen des Features.*/
-  protected Vector<AttributeType> attrTypes = new Vector<AttributeType>();
-
-  /**
-   * Erstellt ein leeres Tabellen-Modell.
-   */
-  public FeatureTypeTableModel() {
-    this(null);
-  }
-
-  /**
-   * Erstellt ein neues Tabellen-Modell.
-   * @param type ein FeatureType
-   */
-  public FeatureTypeTableModel(FeatureType type) {
-    super();
-    setFeatureType( type );
-  }
-
-  /**
-   * Setzt den {@link FeatureType}, der in der Tabelle dargestellt wird.
-   * @param ftype {@link FeatureType}
-   */
-  public void setFeatureType(FeatureType ftype) {
-    this.featureType = ftype;
-    // Attribut-Typen in Array speichern
-    attrTypes.clear();
-    if ( featureType != null )
-      for (int i=0; i<featureType.getAttributeCount(); i++) {
-        AttributeType type = featureType.getAttributeType(i);
-        if ( attrFilter == null || attrFilter.accept( type, i ) )
-          attrTypes.add( type );
-      }
-    this.fireTableDataChanged();
-  }
-
-  /**
-   * Liefert den Filter, der die dargestellten Attribute bestimmt.
-   */
-  public AttributeTypeFilter getAttributeFilter() {
-    return attrFilter;
-  }
-
-  /**
-   * Setzt den Filter, der die dargestellten Attribute bestimmt.
-   * @param attrFilter Filter
-   */
-  public void setAttributeFilter(AttributeTypeFilter attrFilter) {
-    this.attrFilter = attrFilter;
-    // Filter neu anwenden
-    setFeatureType( featureType );
-  }
-
-  /**
-   * Liefert den {@link FeatureType}, der in der Tabelle dargestellt wird.
-   */
-  public FeatureType getFeatureType() {
-    return this.featureType;
-  }
-
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.feature;
 
+import java.util.Vector;
 
-  /**
-   * Liefert die Spaltennamen der Tabelle.
-   */
-  public String[] createColumnNames() {
-    return new String[] {
-        GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.feature.FeatureTableModel.AttrName"),
-        GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.feature.FeatureTableModel.AttrType"),
-    };
-  }
-
-
-  /**
-   * Liefert die Anzahl an Zeilen. Diese entspricht der Anzahl an Attributen
-   * des {@link FeatureType}.
-   */
-  public int getRowCount() {
-    return /*featureType*/attrTypes != null ? attrTypes.size() : 0;
-  }
-
-  /**
-   * Liefert einen Wert der Tabelle.
-   * @param rowIndex  Zeilen-Index (beginnend bei 0)
-   * @param columnIndex Spalten-Index (beginnend bei 0)
-   */
-  public Object getValueAt(int rowIndex, int columnIndex) {
-    AttributeType aType = attrTypes.elementAt(rowIndex);
-    switch ( columnIndex ) {
-      case 0: return aType.getLocalName();
-      case 1: return aType.getBinding().getSimpleName();
-    }
-    return null;
-  }
-}
+import javax.swing.table.TableModel;
+
+import org.geotools.feature.AttributeType;
+import org.geotools.feature.FeatureType;
+
+import schmitzm.geotools.gui.GeotoolsGUIUtil;
+import schmitzm.swing.table.AbstractTableModel;
+
+
+/**
+ * Diese Klasse stellt ein {@link TableModel} auf einem {@link FeatureType}
+ * dar. Dieses definiert zwei Spalten, in denen der Name (0) und der
+ * Typ (1) der Attribute dargestellt werden.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class FeatureTypeTableModel extends AbstractTableModel {
+  /** {@link FeatureType} das in der Tabelle dargestellt wird. */
+  protected FeatureType featureType = null;
+  /** Bestimmt die angezeigten Features */
+  protected AttributeTypeFilter attrFilter = AttributeTypeFilter.ALL;
+
+  /** Speichert die (die gefilterten!) Attibut-Typen des Features.*/
+  protected Vector<AttributeType> attrTypes = new Vector<AttributeType>();
+
+  /**
+   * Erstellt ein leeres Tabellen-Modell.
+   */
+  public FeatureTypeTableModel() {
+    this(null);
+  }
+
+  /**
+   * Erstellt ein neues Tabellen-Modell.
+   * @param type ein FeatureType
+   */
+  public FeatureTypeTableModel(FeatureType type) {
+    super();
+    setFeatureType( type );
+  }
+
+  /**
+   * Setzt den {@link FeatureType}, der in der Tabelle dargestellt wird.
+   * @param ftype {@link FeatureType}
+   */
+  public void setFeatureType(FeatureType ftype) {
+    this.featureType = ftype;
+    // Attribut-Typen in Array speichern
+    attrTypes.clear();
+    if ( featureType != null )
+      for (int i=0; i<featureType.getAttributeCount(); i++) {
+        AttributeType type = featureType.getAttributeType(i);
+        if ( attrFilter == null || attrFilter.accept( type, i ) )
+          attrTypes.add( type );
+      }
+    this.fireTableDataChanged();
+  }
+
+  /**
+   * Liefert den Filter, der die dargestellten Attribute bestimmt.
+   */
+  public AttributeTypeFilter getAttributeFilter() {
+    return attrFilter;
+  }
+
+  /**
+   * Setzt den Filter, der die dargestellten Attribute bestimmt.
+   * @param attrFilter Filter
+   */
+  public void setAttributeFilter(AttributeTypeFilter attrFilter) {
+    this.attrFilter = attrFilter;
+    // Filter neu anwenden
+    setFeatureType( featureType );
+  }
+
+  /**
+   * Liefert den {@link FeatureType}, der in der Tabelle dargestellt wird.
+   */
+  public FeatureType getFeatureType() {
+    return this.featureType;
+  }
+
+
+
+  /**
+   * Liefert die Spaltennamen der Tabelle.
+   */
+  public String[] createColumnNames() {
+    return new String[] {
+        GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.feature.FeatureTableModel.AttrName"),
+        GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.feature.FeatureTableModel.AttrType"),
+    };
+  }
+
+
+  /**
+   * Liefert die Anzahl an Zeilen. Diese entspricht der Anzahl an Attributen
+   * des {@link FeatureType}.
+   */
+  public int getRowCount() {
+    return /*featureType*/attrTypes != null ? attrTypes.size() : 0;
+  }
+
+  /**
+   * Liefert einen Wert der Tabelle.
+   * @param rowIndex  Zeilen-Index (beginnend bei 0)
+   * @param columnIndex Spalten-Index (beginnend bei 0)
+   */
+  public Object getValueAt(int rowIndex, int columnIndex) {
+    AttributeType aType = attrTypes.elementAt(rowIndex);
+    switch ( columnIndex ) {
+      case 0: return aType.getLocalName();
+      case 1: return aType.getBinding().getSimpleName();
+    }
+    return null;
+  }
+}

Modified: trunk/src/schmitzm/geotools/feature/FeatureUtil.java
===================================================================
--- trunk/src/schmitzm/geotools/feature/FeatureUtil.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/feature/FeatureUtil.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,14 +1,32 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package schmitzm.geotools.feature;
 
 

Modified: trunk/src/schmitzm/geotools/feature/NumberValueGenerator.java
===================================================================
--- trunk/src/schmitzm/geotools/feature/NumberValueGenerator.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/feature/NumberValueGenerator.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,68 +1,87 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.geotools.feature;
-
-import org.geotools.feature.AttributeType;
-
-/**
- * This interface represents a generator for {@link Number} values.
- * Starting with an individual value, the next value is increased
- * with every call of {@link #getNextValue()}. The increase interval
- * can also be set individually.
- * @see FeatureUtil#registerAutoValueGenerator(AttributeType, AutoValueGenerator)
- * @see FeatureUtil#getAutoValueGenerator(AttributeType)
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- */
-public class NumberValueGenerator extends AbstractAutoValueGenerator<Number> {
-
-  /** Holds the increment the next value is generated with. */
-  protected Number increment = 0;
-
-  /**
-   * Creates a new generator with first value 0 and increment 1.
-   */
-  public NumberValueGenerator() {
-    this(0);
-  }
-
-  /**
-   * Creates a new generator with increment 1.
-   * @param firstValue first value generated by {@link #generateNextValue()}
-   */
-  public NumberValueGenerator(Number firstValue) {
-    this(firstValue,1);
-  }
-
-  /**
-   * Creates a new generator.
-   * @param firstValue first value generated by {@link #generateNextValue()}
-   * @param increment  increment the next value is generated with (can also be
-   *                   less zero)
-   */
-  public NumberValueGenerator(Number firstValue, Number increment) {
-    super(firstValue == null ? 0 : firstValue);
-    if ( increment.doubleValue() == 0 )
-      throw new IllegalArgumentException("Increment 0 not allowed!");
-    this.increment = increment;
-  }
-
-  /**
-   * Returns the next value.
-   */
-  public Number getNextValue() {
-    if ( lastValue == null )
-      lastValue = firstValue;
-    else
-      lastValue = lastValue.doubleValue() + increment.doubleValue();
-    return lastValue;
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.feature;
+
+import org.geotools.feature.AttributeType;
+
+/**
+ * This interface represents a generator for {@link Number} values.
+ * Starting with an individual value, the next value is increased
+ * with every call of {@link #getNextValue()}. The increase interval
+ * can also be set individually.
+ * @see FeatureUtil#registerAutoValueGenerator(AttributeType, AutoValueGenerator)
+ * @see FeatureUtil#getAutoValueGenerator(AttributeType)
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ */
+public class NumberValueGenerator extends AbstractAutoValueGenerator<Number> {
+
+  /** Holds the increment the next value is generated with. */
+  protected Number increment = 0;
+
+  /**
+   * Creates a new generator with first value 0 and increment 1.
+   */
+  public NumberValueGenerator() {
+    this(0);
+  }
+
+  /**
+   * Creates a new generator with increment 1.
+   * @param firstValue first value generated by {@link #generateNextValue()}
+   */
+  public NumberValueGenerator(Number firstValue) {
+    this(firstValue,1);
+  }
+
+  /**
+   * Creates a new generator.
+   * @param firstValue first value generated by {@link #generateNextValue()}
+   * @param increment  increment the next value is generated with (can also be
+   *                   less zero)
+   */
+  public NumberValueGenerator(Number firstValue, Number increment) {
+    super(firstValue == null ? 0 : firstValue);
+    if ( increment.doubleValue() == 0 )
+      throw new IllegalArgumentException("Increment 0 not allowed!");
+    this.increment = increment;
+  }
+
+  /**
+   * Returns the next value.
+   */
+  public Number getNextValue() {
+    if ( lastValue == null )
+      lastValue = firstValue;
+    else
+      lastValue = lastValue.doubleValue() + increment.doubleValue();
+    return lastValue;
+  }
+
+}

Modified: trunk/src/schmitzm/geotools/feature/resource/locales/FeatureResourceBundle.properties
===================================================================
--- trunk/src/schmitzm/geotools/feature/resource/locales/FeatureResourceBundle.properties	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/feature/resource/locales/FeatureResourceBundle.properties	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,8 +1,37 @@
-# -----------------------------------------------------------
-# ------ Default Translations (english) for components ------
-# ------ in Package schmitzm.geotools.feature          ------
-# -----------------------------------------------------------
-
-# --- Translations for FeatureOperationTree / FeatureOperationTreeParser
-FeatureOperationTree.err.NullAttr=FeatureOperationTree can not evaluate null-Attributes: ${0}
-FeatureOperationTree.err.UnknownAttr=Unknown feature attribute: ${0}
+##########
+#Copyright (c) 2009 Martin O. J. Schmitz.
+#
+#This file is part of the SCHMITZM library - a collection of utility 
+#classes based on Java 1.6, focussing (not only) on Java Swing 
+#and the Geotools library.
+#
+#The SCHMITZM project is hosted at:
+#http://wald.intevation.org/projects/schmitzm/
+#
+#This program is free software; you can redistribute it and/or
+#modify it under the terms of the GNU Lesser General Public License
+#as published by the Free Software Foundation; either version 3
+#of the License, or (at your option) any later version.
+#
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+#
+#You should have received a copy of the GNU Lesser General Public License (license.txt)
+#along with this program; if not, write to the Free Software
+#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#or try this link: http://www.gnu.org/licenses/lgpl.html
+#
+#Contributors:
+#    Martin O. J. Schmitz - initial API and implementation
+#    Stefan A. Krüger - additional utility classes
+##########
+# -----------------------------------------------------------
+# ------ Default Translations (english) for components ------
+# ------ in Package schmitzm.geotools.feature          ------
+# -----------------------------------------------------------
+
+# --- Translations for FeatureOperationTree / FeatureOperationTreeParser
+FeatureOperationTree.err.NullAttr=FeatureOperationTree can not evaluate null-Attributes: ${0}
+FeatureOperationTree.err.UnknownAttr=Unknown feature attribute: ${0}

Modified: trunk/src/schmitzm/geotools/feature/resource/locales/FeatureResourceBundle_de.properties
===================================================================
--- trunk/src/schmitzm/geotools/feature/resource/locales/FeatureResourceBundle_de.properties	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/feature/resource/locales/FeatureResourceBundle_de.properties	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,8 +1,37 @@
-# --------------------------------------------------
-# ------ German Translations for components   ------
-# ------ in Package schmitzm.geotools.feature ------
-# --------------------------------------------------
-
-# --- Translations for FeatureOperationTree / FeatureOperationTreeParser
-FeatureOperationTree.err.NullAttr=FeatureOperationTree keine null-Attribute auswerten: ${0}
-FeatureOperationTree.err.UnknownAttr=Unbekanntes Feature-Attribut: ${0}
+##########
+#Copyright (c) 2009 Martin O. J. Schmitz.
+#
+#This file is part of the SCHMITZM library - a collection of utility 
+#classes based on Java 1.6, focussing (not only) on Java Swing 
+#and the Geotools library.
+#
+#The SCHMITZM project is hosted at:
+#http://wald.intevation.org/projects/schmitzm/
+#
+#This program is free software; you can redistribute it and/or
+#modify it under the terms of the GNU Lesser General Public License
+#as published by the Free Software Foundation; either version 3
+#of the License, or (at your option) any later version.
+#
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+#
+#You should have received a copy of the GNU Lesser General Public License (license.txt)
+#along with this program; if not, write to the Free Software
+#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#or try this link: http://www.gnu.org/licenses/lgpl.html
+#
+#Contributors:
+#    Martin O. J. Schmitz - initial API and implementation
+#    Stefan A. Krüger - additional utility classes
+##########
+# --------------------------------------------------
+# ------ German Translations for components   ------
+# ------ in Package schmitzm.geotools.feature ------
+# --------------------------------------------------
+
+# --- Translations for FeatureOperationTree / FeatureOperationTreeParser
+FeatureOperationTree.err.NullAttr=FeatureOperationTree keine null-Attribute auswerten: ${0}
+FeatureOperationTree.err.UnknownAttr=Unbekanntes Feature-Attribut: ${0}

Modified: trunk/src/schmitzm/geotools/grid/GridStatistic.java
===================================================================
--- trunk/src/schmitzm/geotools/grid/GridStatistic.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/grid/GridStatistic.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,67 +1,85 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.grid;
-
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-import org.geotools.coverage.grid.GridCoverage2D;
-
-/**
- * Diese Klasse stellt Informationen ueber ein Raster dar, die mit
- * {@link GridUtil#determineStatistic(GridCoverage2D,int)} erstellt wurden.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class GridStatistic {
-  /** Breite des Rasters in Zellen.*/
-  public int    widthC    = 0;
-  /** Hoehe des Rasters in Zellen.*/
-  public int    heightC   = 0;
-  /** Kleinster horizontaler Zellen-Index des Rasters (inklusive).*/
-  public int    minX     = 0;
-  /** Kleinster vertikalter Zellen-Index des Rasters (inklusive).*/
-  public int    minY     = 0;
-  /** Groesster horizontaler Zellen-Index des Rasters (exklusive).*/
-  public int    maxX     = 0;
-  /** Groesster vertikaler Zellen-Index des Rasters (exklusive).*/
-  public int    maxY     = 0;
-  /** Reale Breite des Rasters.*/
-  public double widthR    = 0;
-  /** Reale Hoehe des Rasters.*/
-  public double heightR   = 0;
-  /** Latitude der suedwestlichen Ecke.*/
-  public double latSW    = 0;
-  /** Longitude der suedwestlichen Ecke.*/
-  public double lonSW   = 0;
-  /** Breite einer Raster-Zelle.*/
-  public double cellWidth = 0;
-  /** Hoehe des Rasters in Zellen.*/
-  public double cellHeight   = 0;
-  /** Werte, die NoData signalisieren. */
-  public double[] noDataVal = new double[0];
-  /** Kleinster Raster-Wert (ohne NoData-Zellen).*/
-  public double minValue = 0;
-  /** Groesster Raster-Wert (ohne NoData-Zellen).*/
-  public double maxValue = 0;
-  /** Summe aller Raster-Werte (ohne NoData-Zellen).*/
-  public double sumValue = 0;
-  /** Durchschnittlicher Raster-Wert (ohne NoData-Zellen).*/
-  public double avgValue = 0;
-  /** Anzahl an Wert-Zellen */
-  public double cellCnt = 0;
-  /** Anzahl an NoData-Zellen */
-  public double nodataCnt = 0;
-  /** Anzahl an Zellen unterschiedlicher Ausprägung - jede Wert erhält einen Key, Value ist die jeweilige Anzahl der Zellen ohne NaN */
-  public SortedMap<String, Integer> histogramm = new TreeMap<String, Integer>();
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.grid;
+
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.geotools.coverage.grid.GridCoverage2D;
+
+/**
+ * Diese Klasse stellt Informationen ueber ein Raster dar, die mit
+ * {@link GridUtil#determineStatistic(GridCoverage2D,int)} erstellt wurden.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class GridStatistic {
+  /** Breite des Rasters in Zellen.*/
+  public int    widthC    = 0;
+  /** Hoehe des Rasters in Zellen.*/
+  public int    heightC   = 0;
+  /** Kleinster horizontaler Zellen-Index des Rasters (inklusive).*/
+  public int    minX     = 0;
+  /** Kleinster vertikalter Zellen-Index des Rasters (inklusive).*/
+  public int    minY     = 0;
+  /** Groesster horizontaler Zellen-Index des Rasters (exklusive).*/
+  public int    maxX     = 0;
+  /** Groesster vertikaler Zellen-Index des Rasters (exklusive).*/
+  public int    maxY     = 0;
+  /** Reale Breite des Rasters.*/
+  public double widthR    = 0;
+  /** Reale Hoehe des Rasters.*/
+  public double heightR   = 0;
+  /** Latitude der suedwestlichen Ecke.*/
+  public double latSW    = 0;
+  /** Longitude der suedwestlichen Ecke.*/
+  public double lonSW   = 0;
+  /** Breite einer Raster-Zelle.*/
+  public double cellWidth = 0;
+  /** Hoehe des Rasters in Zellen.*/
+  public double cellHeight   = 0;
+  /** Werte, die NoData signalisieren. */
+  public double[] noDataVal = new double[0];
+  /** Kleinster Raster-Wert (ohne NoData-Zellen).*/
+  public double minValue = 0;
+  /** Groesster Raster-Wert (ohne NoData-Zellen).*/
+  public double maxValue = 0;
+  /** Summe aller Raster-Werte (ohne NoData-Zellen).*/
+  public double sumValue = 0;
+  /** Durchschnittlicher Raster-Wert (ohne NoData-Zellen).*/
+  public double avgValue = 0;
+  /** Anzahl an Wert-Zellen */
+  public double cellCnt = 0;
+  /** Anzahl an NoData-Zellen */
+  public double nodataCnt = 0;
+  /** Anzahl an Zellen unterschiedlicher Ausprägung - jede Wert erhält einen Key, Value ist die jeweilige Anzahl der Zellen ohne NaN */
+  public SortedMap<String, Integer> histogramm = new TreeMap<String, Integer>();
+
+}

Modified: trunk/src/schmitzm/geotools/grid/GridUtil.java
===================================================================
--- trunk/src/schmitzm/geotools/grid/GridUtil.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/grid/GridUtil.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,893 +1,911 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.grid;
-
-import java.awt.Color;
-import java.awt.Point;
-import java.awt.Rectangle;
-import java.awt.geom.Point2D;
-import java.awt.image.ComponentSampleModel;
-import java.awt.image.DataBuffer;
-import java.awt.image.Raster;
-import java.awt.image.RenderedImage;
-import java.awt.image.WritableRaster;
-import java.text.DecimalFormat;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Hashtable;
-import java.util.Map;
-import java.util.Set;
-
-import org.apache.log4j.Category;
-import org.apache.log4j.Logger;
-import org.geotools.coverage.FactoryFinder;
-import org.geotools.coverage.GridSampleDimension;
-import org.geotools.coverage.grid.GridCoverage2D;
-import org.geotools.coverage.grid.GridCoverageFactory;
-import org.geotools.coverage.grid.GridGeometry2D;
-import org.geotools.geometry.Envelope2D;
-import org.geotools.styling.ColorMap;
-import org.geotools.styling.RasterSymbolizer;
-import org.geotools.styling.Style;
-import org.geotools.styling.StyleBuilder;
-import org.opengis.coverage.PointOutsideCoverageException;
-import org.opengis.coverage.SampleDimension;
-import org.opengis.coverage.grid.GridRange;
-import org.opengis.geometry.Envelope;
-
-import schmitzm.data.WritableGrid;
-import schmitzm.data.WritableGridArray;
-import schmitzm.geotools.GTUtil;
-import schmitzm.geotools.styling.StylingUtil;
-import schmitzm.lang.LangUtil;
-import schmitzm.swing.SwingUtil;
-
-import com.vividsolutions.jts.geom.Coordinate;
-import com.vividsolutions.jts.geom.Geometry;
-import com.vividsolutions.jts.geom.GeometryFactory;
-import com.vividsolutions.jts.geom.LineString;
-
-/**
- * Diese Klasse stellt statische Funktionen fuer die Arbeit mit
- * {@linkplain GridCoverage2D Rasterdaten} zur Verfuegung.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.01
- */
-public class GridUtil {
-
-        /** log4j initialize */
-        private static final Category cCat = Logger.getLogger(GridUtil.class.getName());
-
-      public static final GridCoverageFactory GRID_FAC = new GridCoverageFactory();
-
-	/**
-	 * The default name for style created by createDefaultStyle();
-	 */
-	  public static final String DEFAULT_RASTER_STYLE_NAME = "default raster style";
-	  public static final String DEFAULT_RASTER_STYLE_TITLE = "default raster style";
-	  public static final String UNNAMED_RASTER_STYLE_NAME = "unnamed raster style";
-	  public static final String UNTITLED_RASTER_STYLE_TITLE = "untitled raster style";
-
-	  /**
-	   * 11 Default colors used by {@link #createDiscreteStyle(GridCoverage2D, double, Color...)} if
-	   * no colors are given.
-	   * <ol>
-	   *   <li>White</li>
-	   *   <li>Red</li>
-	   *   <li>Blue</li>
-	   *   <li>Yellow</li>
-	   *   <li>Green</li>
-	   *   <li>Gray</li>
-	   *   <li>Orange</li>
-	   *   <li>Pink</li>
-	   *   <li>Magenta</li>
-       *   <li>Light gray</li>
-	   *   <li>Cyan</li>
-	   *   <li>Black</li>
-	   * </ol>
-	   */
-      public static final Color[] DEFAULT_COLORS = new Color[] {
-          Color.WHITE,
-          Color.RED,
-          Color.BLUE,
-          Color.YELLOW,
-          Color.GREEN,
-          Color.GRAY,
-          Color.ORANGE,
-          Color.PINK,
-          Color.MAGENTA,
-          Color.LIGHT_GRAY,
-          Color.CYAN,
-          Color.BLACK
-      };
-
-
-      /**
-	   * Liefert statistische Daten ueber ein Grid und erstellt ein Histogramm
-	   * @param gc ein Raster
-	   * @param band zu untersuchendes Band
-	   * @param histogramSteps Schritte des Histogramms, -1 wenn alle Ausprägungen, 0 für ohne Histogramm
-	   * @param histogrammDigits Anzahl an Nachkommastellen auf die die Histogramm-Klassen gerundet werden
-	   *                         (negative Werte = Vorkommastellen; null = kein Runden). Nur relevant, wenn
-	   *                         {@code hishistogramSteps} = -1
-	   * @author Martin Schmitz
-	   * @author Andreas Enders
-	   */
-	  public static GridStatistic determineStatistic(GridCoverage2D gc, int band, int histogramSteps, Integer histogrammDigits) {
-	    GridStatistic gs = new GridStatistic();
-	    GridRange     gr = gc.getGridGeometry().getGridRange();
-	    Envelope2D    ev = gc.getEnvelope2D();
-	    gs.minX          = gr.getLower(0);
-	    gs.minY          = gr.getLower(1);
-	    gs.maxX          = gr.getUpper(0);
-	    gs.maxY          = gr.getUpper(1);
-	    gs.widthC        = gs.maxX - gs.minX;
-	    gs.heightC       = gs.maxY - gs.minY;
-	    gs.widthR        = ev.getLength(0);
-	    gs.heightR       = ev.getLength(1);
-	    gs.latSW         = ev.getX();
-	    gs.lonSW         = ev.getY();
-	    gs.cellWidth     = (gs.widthC != 0) ? gs.widthR / gs.widthC : 0;
-	    gs.cellHeight    = (gs.heightC != 0) ? gs.heightR / gs.heightC : 0;
-
-	    gs.nodataCnt     = 0;
-	    gs.cellCnt       = 0;
-	    gs.noDataVal     = gc.getSampleDimensions()[band].getNoDataValues();
-	    if ( gs.noDataVal == null )
-	      gs.noDataVal = new double[0];
-	    gs.sumValue      = 0;
-
-
-	    // Check auf NoData-Zellen erfolgt ueber Hash-Tabelle
-	    Hashtable isNoData = new Hashtable<Double,Boolean>(gs.noDataVal.length);
-	    for (int i=0; i<gs.noDataVal.length; i++)
-	      isNoData.put(gs.noDataVal[i],true);
-
-	    // Objekte fuer Koordinate
-	    Point2D  p        = new Point2D.Float();
-	    double[] val      = new double[ gc.getSampleDimensions().length ];
-
-	    double lon = gs.lonSW + gs.cellHeight/2;
-	    for (int y=gs.minY; y<gs.maxY; y++, lon+=gs.cellHeight) {
-	      double lat = gs.latSW + gs.cellWidth/2;
-	      for (int x=gs.minX; x<gs.maxX; x++, lat+=gs.cellWidth) {
-	        p.setLocation(lat,lon);
-	        gc.evaluate(p,val);
-	        // NoData-Zellen gehen nicht in die Statistik ein
-	        if ( Double.isNaN(val[band]) || isNoData.containsKey(val[band]) )
-	          gs.nodataCnt++;
-	        else {
-	          gs.minValue = Math.min(gs.minValue, val[band]);
-	          gs.maxValue = Math.max(gs.maxValue, val[band]);
-	          gs.sumValue += val[band];
-	          gs.cellCnt++;
-	        }
-	      }
-	    }
-	    //histogramm berechnen, wenn nicht ausgeschaltet
-	    if (histogramSteps != 0)
-	    {
-	      lon = gs.lonSW + gs.cellHeight/2;
-	      for (int y=gs.minY; y<gs.maxY; y++, lon+=gs.cellHeight)
-	      {
-	        double lat = gs.latSW + gs.cellWidth/2;
-	        for (int x=gs.minX; x<gs.maxX; x++, lat+=gs.cellWidth)
-	        {
-	          p.setLocation(lat,lon);
-	          gc.evaluate(p,val);
-	          // NoData-Zellen gehen nicht in die Statistik ein
-	          if ( !Double.isNaN(val[band]) && !isNoData.containsKey(val[band]) )
-	          {
-	            double tVal = val[band];
-	            if (histogramSteps < 0)
-	            {
-	              //String tValue = ""+(new Double(tVal).longValue());
-	              String value = String.valueOf( histogrammDigits != null ? LangUtil.round(tVal,histogrammDigits) : tVal );
-	              Integer pixelCount = gs.histogramm.get(value);
-	              if (pixelCount == null)
-	                pixelCount = 1;
-	              else
-	                pixelCount++;
-	              gs.histogramm.put(value, pixelCount);
-	            }
-	            else
-	            {
-	              double stepRange = (gs.maxValue - gs.minValue)/histogramSteps;
-	              int step = new Double((tVal - gs.minValue)/stepRange).intValue();
-	              String stepName = ""+gs.minValue + step * stepRange;
-	              Integer number = gs.histogramm.get(stepName);
-	              if (number == null) number = 1;
-	              else number++;
-	              gs.histogramm.put(stepName, number);
-	            }
-	          }
-	        }
-	      }
-              cCat.debug("Histogram created with map: "+gs.histogramm);
-	    }
-	    // Durchschnittswert berechnen (nicht ueber NoData-Zellen)
-	    gs.avgValue = (gs.cellCnt != 0) ? gs.sumValue/gs.cellCnt : 0;
-
-	    return gs;
-	  }
-
-
-      /**
-       * Liefert statistische Daten ueber ein Grid und erstellt ein Histogramm.
-       * Die Histogramm-Klassen werden auf ganze Zahlen gerundet.
-       * @param gc ein Raster
-       * @param band zu untersuchendes Band
-       * @param histogramSteps Schritte des Histogramms, -1 wenn alle Ausprägungen, 0 für ohne Histogramm
-       * @author Martin Schmitz
-       * @author Andreas Enders
-       */
-      public static GridStatistic determineStatistic(GridCoverage2D gc, int band, int histogramSteps) {
-        return determineStatistic(gc, band, histogramSteps, 0);
-      }
-
-  /**
-   * Liefert statistische Daten ueber ein Grid, ohne ein Histogram zu berechnen.
-   * @param gc ein Raster
-   * @param band zu untersuchendes Band
-   */
-  public static GridStatistic determineStatistic(GridCoverage2D gc, int band) {
-	  return determineStatistic(gc, band, 0);
-  }
-
-  /**
-   * Liefert statistische Daten ueber ein Grid, das in Zonen unterteilt ist.
-   * Die Zonen werden durch einen {@link Float}-Wert identifiziert, damit
-   * auch NoData-Werte in einem Raster einer Zone (naemlich der
-   * Zone {@code Float.NaN}) zugewiesen werden koennen.
-   * @param valueGC Raster ueber das die Statistik erzeugt wird
-   * @param zoneGC Raster, das die Zonen bestimmt
-   */
-  public static GridZoneStatistic<Float> determineZoneStatistic(GridCoverage2D valueGC, GridCoverage2D zoneGC) {
-    return determineZoneStatistic(valueGC, 0, zoneGC, 0);
-  }
-
-  /**
-   * Liefert statistische Daten ueber ein Grid, das in Zonen unterteilt ist.
-   * Die Zonen werden durch einen {@link Float}-Wert identifiziert, damit
-   * auch NoData-Werte in einem Raster einer Zone (naemlich der
-   * Zone {@code Float.NaN}) zugewiesen werden koennen.
-   * @param valueGC Raster ueber das die Statistik erzeugt wird
-   * @param valueBand Band ueber das die Statistik erzeugt wird
-   * @param zoneGC Raster, das die Zonen bestimmt
-   * @param zoneBand Band, das die Zonen bestimmt
-   */
-  public static GridZoneStatistic<Float> determineZoneStatistic(GridCoverage2D valueGC, int valueBand, GridCoverage2D zoneGC, int zoneBand) {
-    final ReadableGridCoverage zoneGrid  = ReadableGridCoverage.create(zoneGC, 0);
-
-    // Performanz: Raster-Ausmasse in lokalen Variablen speichern
-    final float         cellHeight = (float)zoneGrid.getCellHeight();
-    final float         cellWidth  = (float)zoneGrid.getCellHeight();
-    final float         minX       = (float)zoneGrid.getX() + cellWidth/2;
-    final float         maxX       = (float)(zoneGrid.getX() + zoneGrid.getRealWidth());
-    final float         minY       = (float)zoneGrid.getY() + cellHeight/2;
-    final float         maxY       = (float)(zoneGrid.getY() + zoneGrid.getRealHeight());
-
-//    // Solution without WritableGrid
-//    final Envelope2D    env        = zoneGC.getEnvelope2D();
-//    final GridRange     gr         = zoneGC.getGridGeometry().getGridRange();
-//    final float         height     = (float)env.getHeight();
-//    final float         width      = (float)env.getWidth();
-//    final int           heightC    = Math.abs( gr.getLower(1) - gr.getUpper(1) );
-//    final int           widthC     = Math.abs( gr.getLower(0) - gr.getUpper(0) );
-//    final float         cellHeight = heightC != 0 ? height / heightC : 0;
-//    final float         cellWidth  = widthC  != 0 ? width  / widthC  : 0;
-//    final float         minX       = (float)env.getX() + cellWidth/2;
-//    final float         maxX       = (float)(env.getX() + width);
-//    final float         minY       = (float)env.getY() + cellHeight/2;
-//    final float         maxY       = (float)(env.getY() + height);
-
-    final Point2D.Float loc        = new Point2D.Float();
-    // Arrays zum Speichern der Rasterwerte pro Band
-    final float[]  zoneGridVal  = new float[zoneGC.getNumSampleDimensions()];
-    final float[]  valueGridVal = new float[zoneGC.getNumSampleDimensions()];
-    // Variablen zum Speichern des Band-Werts
-    float zoneNo  = 0;
-    float cellVal = 0;
-
-    // Zonen-Statistik berechnen
-    GridZoneStatistic    zoneStat  = new GridZoneStatistic<Float>();
-    for (loc.y=minY; loc.y<maxY; loc.y+=cellHeight)
-      for (loc.x=minX; loc.x<=maxX; loc.x+=cellWidth) {
-        zoneGC.evaluate(loc, zoneGridVal);
-        zoneNo = zoneGridVal[zoneBand];
-        try {
-          valueGC.evaluate(loc, valueGridVal);
-          cellVal = valueGridVal[valueBand];
-          zoneStat.addValueToZoneStatistic(zoneNo, cellVal);
-        } catch (PointOutsideCoverageException err) {
-          // Zonen-Zelle liegt ausserhalb des Wert-Rasters
-          // --> Zelle ignorieren
-        }
-      }
-
-    return zoneStat;
-  }
-
-  /**
-   * Erzeugt einen Standard-Style fuer ein {@link GridCoverage2D}
-   * und setzt den default-Namen: GridUtil.DEFAULT_RASTER_STYLE_NAME
-   * Und eine title : GridUtil.DEFAULT_RASTER_STYLE_TITLE
-   *
-   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-   * @author Stefan Alfons Krüger (DEFAULT_RASTER_STYLE_NAME, DEFAULT_RASTER_STYLE_TITLE)
-   */
-  public static Style createDefaultStyle() {
-    Style defaultStyle = createStyle(null,1.0);
-    defaultStyle.setName(DEFAULT_RASTER_STYLE_NAME);
-    defaultStyle.setTitle(DEFAULT_RASTER_STYLE_TITLE);
-	return( defaultStyle );
-  }
-
-  /**
-   * Erzeugt einen Standard-Style fuer ein {@link GridCoverage2D}
-   * @param colorMap Farb-Palette
-   * @param opacity  Transparenz (1.0 = vollfarbig)
-   * @return ein Standard-Style ( {@code StyleBuilder.createRasterSymbolizer()}) falls
-   *         keine ColorMap angegeben wird
-   */
-  public static Style createStyle(ColorMap colorMap, double opacity) {
-    StyleBuilder builder = StylingUtil.STYLE_BUILDER;
-    RasterSymbolizer symb = colorMap != null ? builder.createRasterSymbolizer(colorMap,opacity) : builder.createRasterSymbolizer();
-    return( builder.createStyle( symb ) );
-  }
-
-  /**
-   * Creates an interpolative style for a {@link GridCoverage2D}. The given colors
-   * are interpolated from the minimum to the maximum raster value.
-   * @param grid     the raster
-   * @param opacity  opacity for the style
-   * @param colors   colors to interpolate with (at least 2)
-   */
-  public static Style createInterpolativeStyle(GridCoverage2D grid, double opacity, Color... colors) {
-    if ( colors.length < 2 )
-      throw new IllegalArgumentException("At least 2 colors must be specified for an interpolative style.");
-    GridStatistic gridStat  = GridUtil.determineStatistic(grid, 0);
-    double   intervalLength = gridStat.maxValue - gridStat.minValue;
-    String[] labels         = new String[colors.length];
-    double[] values         = new double[colors.length];
-    for (int i=0; i<colors.length; i++) {
-      labels[i] = ""; // all categories must have the same label
-      values[i] = gridStat.minValue + intervalLength * i/(colors.length-1.0);
-    }
-    ColorMap colorMap = StylingUtil.STYLE_BUILDER.createColorMap(
-        labels,
-        values,
-        colors,
-        ColorMap.TYPE_RAMP
-    );
-    RasterSymbolizer rasterSymb = StylingUtil.STYLE_BUILDER.createRasterSymbolizer(colorMap, opacity);
-    return StylingUtil.STYLE_BUILDER.createStyle( rasterSymb );
-  }
-
-  /**
-   * Creates a discrete style for a {@link GridCoverage2D}. For every value
-   * in the raster another color is choosen. If the raster contains more values
-   * than colors are given, all surplus values are mapped to the "last" color.
-   * @param grid          the raster
-   * @param opacity       opacity for the style
-   * @param digits        number of digits the grid value classes (and legend) are
-   *                      rounded to (null means no round; >= 0 means digits after comma;
-   *                      < 0 means digits before comma)
-   * @param colorPalette  colors for the values (the smallest value is mapped to index 0, the second
-   *                      smallest to index 1, ...); if no colors are specified {@link #DEFAULT_COLORS}
-   *                      are used
-   */
-  public static Style createDiscreteStyle(GridCoverage2D grid, double opacity, Integer digits, Color... colorPalette) {
-    if ( colorPalette.length == 0 )
-      colorPalette = DEFAULT_COLORS;
-    DecimalFormat decFormat = digits != null ? new DecimalFormat( SwingUtil.getNumberFormatPattern(digits) ) : null;
-    GridStatistic gridStat  = GridUtil.determineStatistic(grid, 0, -1, digits);
-
-    int      valueCount = gridStat.histogramm.size();
-    String[] labels     = new String[valueCount];
-    double[] values     = new double[valueCount];
-    Color[]  colors     = new Color[valueCount];
-    Color    lastColor  = colorPalette[colorPalette.length-1];
-
-    int i = -1;
-    for (String key : gridStat.histogramm.keySet()) {
-      i++;
-      values[i] = Double.parseDouble(key);
-      colors[i] = i < colorPalette.length ? colorPalette[i] : lastColor;
-      if ( decFormat != null )
-        labels[i] = decFormat.format(values[i]);
-      else
-        labels[i] = String.valueOf(values[i]);
-      //labels[i] += " ("+gridStat.histogramm.get(key)+" pixel)";
-    }
-
-    ColorMap tColorMap = StylingUtil.STYLE_BUILDER.createColorMap(
-        labels,
-        values,
-        colors,
-        ColorMap.TYPE_VALUES
-    );
-
-    RasterSymbolizer rasterSymb = StylingUtil.STYLE_BUILDER.createRasterSymbolizer(tColorMap, opacity);
-    return StylingUtil.STYLE_BUILDER.createStyle( rasterSymb );
-  }
-
-  /**
-   * Kopiert ein {@link GridCoverage2D} komplett.
-   * @param source Quell-Raster
-   */
-  public static GridCoverage2D copyGridCoverage(GridCoverage2D source) {
-    //return createGridCoverage(source,source.getEnvelope());
-    return GRID_FAC.create(
-        source.getName(),
-        source.getRenderedImage().copyData(null),
-        source.getEnvelope()
-    );
-  }
-
-  /**
-   * Kopiert ein {@link GridCoverage2D} komplett, dessen Raster-Koordinaten
-   * (obere-linke Ecke) transformiert wird.
-   * @param source Quell-Raster
-   * @param minX   neue Raster-Koordinate fuer die obere linke Ecke
-   * @param minY   neue Raster-Koordinate fuer die obere linke Ecke
-   */
-  public static GridCoverage2D copyGridCoverage(GridCoverage2D source, int minX, int minY) {
-    return GRID_FAC.create(
-                      source.getName(),
-                      source.getRenderedImage().copyData(null).createWritableTranslatedChild(minX, minY),
-                      source.getEnvelope()
-           );
-  }
-
-  /**
-   * Erzeugt ein neues {@link GridCoverage2D} mit neuer {@link SampleDimension}.
-   * @param gc        Raster (mit nur einem Band)
-   * @param sampleDim neue {@link SampleDimension}
-   * @return eine neue {@link GridCoverage2D}-Instanz
-   */
-  public static GridCoverage2D resampleGridCoverage(GridCoverage2D gc, GridSampleDimension sampleDim) {
-    return resampleGridCoverage(gc, new GridSampleDimension[] {sampleDim});
-  }
-
-  /**
-   * Erzeugt ein neues {@link GridCoverage2D} mit neuer {@link SampleDimension}.
-   * @param gc        Raster
-   * @param sampleDim neue {@link SampleDimension}
-   * @return eine neue {@link GridCoverage2D}-Instanz
-   */
-  public static GridCoverage2D resampleGridCoverage(GridCoverage2D gc, GridSampleDimension[] sampleDim) {
-    final Map properties = new HashMap();
-    //  properties.put("GC_NODATA", -9999.0);
-
-    return FactoryFinder.getGridCoverageFactory(null).create(
-        gc.getName(),
-        gc.getRenderedImage(),
-        (GridGeometry2D)gc.getGridGeometry(),
-        sampleDim,
-        null, //new GridCoverage[] { raster },
-        properties
-    );
-  }
-
-  /**
-   * Erzeugt ein {@link GridCoverage2D} aus einem anderen. Das neue Raster
-   * hat maximal die Ausmasse des Quell-Rasters.
-   * @param source Quell-Raster
-   * @param bboxEnv Bounding-Box (beschreibt die den Ausschnitt des Quell-Rasters aus dem
-   *                das neue Raster erzeugt wird)
-   * @return {@code null} falls sich das Quell-Raster und die Bounding-Box nicht
-   *         ueberschneiden.
-   */
-  public static GridCoverage2D createGridCoverage(GridCoverage2D source, Envelope bboxEnv) {
-    Envelope2D sourceEnv = source.getEnvelope2D();
-    // Subset nur bzgl. des Bereichs in dem auch das Raster liegt
-    bboxEnv = GTUtil.intersectEnvelope(sourceEnv,bboxEnv,source.getCoordinateReferenceSystem());
-    if ( bboxEnv.getLength(0) == 0 && bboxEnv.getLength(1) == 0 )
-      return null;
-
-    // Daten des Source-Raster
-    double realMinX     = sourceEnv.getX();
-    double realMinY     = sourceEnv.getY();
-    double realWidth    = sourceEnv.getWidth();
-    double realHeight   = sourceEnv.getHeight();
-    int    rasterMinX   = source.getRenderedImage().getMinX();
-    int    rasterMinY   = source.getRenderedImage().getMinY();
-    int    rasterWidth  = source.getRenderedImage().getWidth();
-    int    rasterHeight = source.getRenderedImage().getHeight();
-    double cellWidth    = realWidth / rasterWidth;
-    double cellHeight   = realHeight / rasterHeight;
-
-    // Envelope in Raster-Koordinaten (bzgl. unterer linker Ecke!)
-    int subsetLX = convertRealToRaster(bboxEnv.getLowerCorner().getOrdinate(0),realMinX,realWidth,rasterMinX,rasterWidth);
-    int subsetLY = convertRealToRaster(bboxEnv.getLowerCorner().getOrdinate(1),realMinY,realHeight,rasterMinY,rasterHeight);
-    int subsetUX = convertRealToRaster(bboxEnv.getUpperCorner().getOrdinate(0),realMinX,realWidth,rasterMinX,rasterWidth);
-    int subsetUY = convertRealToRaster(bboxEnv.getUpperCorner().getOrdinate(1),realMinY,realHeight,rasterMinY,rasterHeight);
-    int subsetW  = Math.abs(subsetLX-subsetUX)+1;
-    int subsetH  = Math.abs(subsetLY-subsetUY)+1;
-    // obere linke Ecke des Subsets in Raster-Koordinaten
-    int ulX = Math.min(subsetLX,subsetUX);
-    int ulY = rasterMinY+rasterHeight - Math.max(subsetLY,subsetUY) -1;
-
-    // WritableRaster fuer Subset erstellen
-    Rectangle       rect = new Rectangle(ulX,ulY,subsetW,subsetH);
-    Raster          r    = source.getRenderedImage().getData( rect );
-    WritableRaster  wr   = createWritableRaster(r);
-
-    // Envelope fuer Subset erzeugen (bzgl. untere liner Ecke!)
-    Envelope subsetEnv = new Envelope2D(
-        source.getCoordinateReferenceSystem(),
-        convertRasterToReal(subsetLX,rasterMinX,realMinX,cellWidth)-cellWidth/2,
-        convertRasterToReal(subsetLY,rasterMinY,realMinY,cellHeight)-cellHeight/2,
-        subsetW * cellWidth,
-        subsetH * cellHeight
-    );
-
-    return new GridCoverageFactory().create("",wr,subsetEnv);
-  }
-
-
-  /**
-   * Erzeugt ein {@link WritableRaster} aus einem {@link Raster}.
-   * @param r Raster
-   * @param minX Start-Index in X-Richtung
-   * @param minY Start-Index in Y-Richtung
-   */
-  public static WritableRaster createWritableRaster(Raster r, int minX, int minY) {
-    return Raster.createWritableRaster(
-        new ComponentSampleModel(r.getDataBuffer().getDataType(),
-                                 r.getWidth(),
-                                 r.getHeight(),
-                                 1,
-                                 r.getWidth(),
-                                 new int[] {0}),
-        r.getDataBuffer(),
-        new Point(minX,minY)
-    );
-  }
-
-  /**
-   * Erzeugt ein {@link WritableRaster} aus einem {@link Raster}.
-   * @param r Raster
-   */
-  public static WritableRaster createWritableRaster(Raster r) {
-    return createWritableRaster(r,0,0);
-  }
- 
-  /**
-   * Konvertiert ein Raster-Objekt in eine {@link GridCoverage2D}.
-   * Es werden folgende Objekt-Typen unterstuetzt:
-   * <ul>
-   *   <li>Instanzen von {@link GridCoverage2D}</li>
-   *   <li>Instanzen von {@link WritableRaster} <u>und</u> {@link WritableGrid}</li>
-   *   <li>Instanzen von {@link WritableGridArray}</li>
-   * </ul>
-   * @param obj Object
-   * @exception IllegalArgumentException falls das Objekt nicht konvertiert werden kann
-   */
-  public static GridCoverage2D convertToGridCoverage2D(Object obj) {
-    if ( obj instanceof GridCoverage2D )
-      return (GridCoverage2D)obj;
-
-    if ( obj instanceof WritableRaster  && obj instanceof WritableGrid ) {
-      // GT-GridCoverage aus WritableGridRaster erzeugen
-      WritableRaster wr = (WritableRaster)obj;
-      WritableGrid   wg = (WritableGrid)obj;
-      Envelope2D     ev = new Envelope2D(wg.getCoordinateReferenceSystem(),wg.getX(),wg.getY(),wg.getRealWidth(),wg.getRealHeight());
-      return new GridCoverageFactory().create("",wr,ev);
-    }
-
-    if ( obj instanceof WritableGridArray ) {
-      // GT-GridCoverage aus WritableGridRaster erzeugen
-      WritableGridArray wga = (WritableGridArray)obj;
-      Envelope2D        ev = GTUtil.createEnvelope2D(wga.getEnvelope(),wga.getCoordinateReferenceSystem());
-      WritableRaster    wr = Raster.createWritableRaster(
-          new ComponentSampleModel(wga.getSampleType(),
-                                   wga.getWidth(),
-                                   wga.getHeight(),
-                                   1,
-                                   wga.getWidth(),
-                                   new int[] {0}
-          ),
-          wga.getDataBuffer(),
-          new Point(0,0)
-      );
-      return new GridCoverageFactory().create("",wr,ev);
-    }
-
-    throw new IllegalArgumentException("Object can not be converted to GridCoverage2D: "+(obj==null ? "null" : obj.getClass().getSimpleName()));
-
-  }
-
-
-  /**
-   * Converts a real world coordinate to the row/column number of a raster.
-   * If the coordinate value is exactly located on the border between two
-   * cells, the next greater raster cell is returned (except the raster border:
-   * the lower (=last) cell is returned).<br>
-   * This method can be applied on all dimensions (X or Y or ...), if the
-   * accordingly input parameter for the dimension are given.<br>
-   * <b>Note:</b>
-   * Because this method is independed from the dimension, it assumes that the
-   * "beginning" of the raster coordinates is located in the same corner like
-   * the lat/lon-refernce!! 
-   * @param coord        geographic reference (world coordinate), which is converted
-   * @param realMin      minimal world coordinate of the raster
-   * @param realLength   length of the raster in "world coordinates"
-   * @param rasterMin    index of the first raster cell (normally 0)
-   * @param rasterLength size of the raster (in cells)
-   * @exception UnsupportedOperationException falls als {@code rasterLength} 0
-   *            uebergeben wird
-   */
-  public static int convertRealToRaster(final double coord, final double realMin, final double realLength, final int rasterMin, final int rasterLength) {
-    if ( rasterLength <= 0 )
-      throw new UnsupportedOperationException("Length of raster must be > 0!");
-    final double cellSize = realLength / rasterLength;
-
-    // Wenn Koordinate genau den Rasterrand trifft, wird die letzte
-    // Zelle zurueckgegeben...
-    if ( coord == realMin + realLength )
-      return rasterMin + rasterLength - 1;
-    // ... sonst die naechste Zelle
-    // Bemerkung: Einfaches Abschneiden (int) reicht nicht, es muss die
-    //            naechstkleinere Zahl ermittelt werden, denn sonst gibt
-    //            es die Zelle 0 zweimal, z.B.
-    //              (coord-realMin)/cellSize =  0.8 --> Zelle 0 (korrekt)
-    //              (coord-realMin)/cellSize = -0.8 --> Zelle 0 (falsch)
-    //            Im zweiten Fall muss auf -1 "gerundet" werden!
-    return ((int)Math.floor( (coord-realMin) / cellSize ) ) + rasterMin;
-  }
-
-  /**
-   * Converts a raster cell index to "real" world coordinates. The coordinate
-   * of the cell center is returned.<br> 
-   * This method can be applied on all dimensions (X or Y or ...), if the
-   * accordingly input parameter for the dimension are given.<br>
-   * <b>Note:</b>
-   * Because this method is independed from the dimension, it assumes that the
-   * "beginning" of the raster coordinates is located in the same corner like
-   * the lat/lon-refernce!! 
-   * @param cell       raster index, which is converted
-   * @param rasterMin  minimal index of the raster
-   * @param realMin    minimal world coordinate of the raster
-   * @param cellSize   size of one cell in "world coordinates"
-   */
-  public static double convertRasterToReal(final int cell, final int rasterMin, final double realMin, final double cellSize) {
-    return realMin + (cell-rasterMin)*cellSize + 0.5*cellSize;
-  }
-
-  /**
-   * Converts a geo reference to raster coordinates.
-   * @param gc   source raster
-   * @param geoX Longitude to be converted
-   * @param geoY Latitude to be converted
-   * @return 2-dimensional array with the X-index in element 0 and the Y-index in
-   *         element 1
-   */
-  public static int[] convertRealToRaster(GridCoverage2D gc, double geoX, double geoY) {
-    return convertRealToRaster(gc, new double[] { geoX, geoY } );
-  }
-
-  /**
-   * Converts a geo reference to raster coordinates.
-   * @param env      geo reference of the raster
-   * @param image    image of the raster
-   * @param geoX     Longitude to be converted
-   * @param geoY     Latitude to be converted
-   * @return 2-dimensional array with the X-index in element 0 and the Y-index in
-   *         element 1
-   */
-  public static int[] convertRealToRaster(Envelope2D env, RenderedImage image, double geoX, double geoY) {
-    return convertRealToRaster(env, image, new double[] { geoX, geoY } );
-  }
-
-  /**
-   * Converts a geo reference to raster coordinates.
-   * @param gc   source raster
-   * @param geoCoord geo reference (Longitude,Latitude) to be converted
-   * @return 2-dimensional array with the X-index in element 0 and the Y-index in
-   *         element 1
-   */
-  public static int[] convertRealToRaster(GridCoverage2D gc, double[] geoCoord) {
-    return convertRealToRaster(gc.getEnvelope2D(), gc.getRenderedImage(), geoCoord);
-  }
-
-  /**
-   * Converts a geo reference to raster coordinates.
-   * @param env      geo reference of the raster
-   * @param image    image of the raster
-   * @param geoCoord geo reference (Longitude,Latitude) to be converted
-   * @return 2-dimensional array with the X-index in element 0 and the Y-index in
-   *         element 1
-   */
-  public static int[] convertRealToRaster(Envelope2D env, RenderedImage image, double[] geoCoord) {
-    final double realMinX = env.getX();
-    final double realMinY = env.getY();
-    final double realWidth = env.getWidth();
-    final double realHeight = env.getHeight();
-    final int    rasterMinX = image.getMinX();
-    final int    rasterMinY = image.getMinY();
-    final int    rasterWidth = image.getWidth();
-    final int    rasterHeight = image.getHeight();
-
-    int cellX = convertRealToRaster(geoCoord[0],realMinX,realWidth,rasterMinX,rasterWidth);
-    int cellY = convertRealToRaster(geoCoord[1],realMinY,realHeight,rasterMinY,rasterHeight);
-    // Ursprung der Raster-Koord. ist OBEN LINKS
-    cellY = rasterMinY+rasterHeight - cellY - 1;
-
-    return new int[] {cellX, cellY};
-  }
-
-
-  /**
-   * Determines the raster cells, which are intersected by a {@link LineString}.
-   * @param gc the raster
-   * @param ls {@link LineString} to check
-   * @param result Set the intersected cells are inserted in (can be {@code null})
-   * @return an empty set if the LineString is located outside the raster
-   */
-  public static Set<Point> getOverlappingCells(GridCoverage2D gc, LineString ls, Set<Point> result) {
-    if ( result == null )
-      result = new HashSet<Point>();
-
-    Envelope2D gridEnv      = gc.getEnvelope2D();
-    double     realMinX     = gridEnv.getX();
-    double     realMinY     = gridEnv.getY();
-    double     realWidth    = gridEnv.getWidth();
-    double     realHeight   = gridEnv.getHeight();
-    double     realMaxX     = realMinX + realWidth;
-    double     realMaxY     = realMinY + realHeight;
-    int        rasterMinX   = gc.getRenderedImage().getMinX();
-    int        rasterMinY   = gc.getRenderedImage().getMinY();
-    int        rasterWidth  = gc.getRenderedImage().getWidth();
-    int        rasterHeight = gc.getRenderedImage().getHeight();
-    double     cellWidth    = realWidth / rasterWidth;
-    double     cellHeight   = realHeight / rasterHeight;
-
-    Coordinate[]    cellBounds = new Coordinate[] { new Coordinate(), new Coordinate(), new Coordinate(), new Coordinate() };
-    GeometryFactory geomFac    = new GeometryFactory();
-
-    // determine the cells of the LineStrings start/end point
-    com.vividsolutions.jts.geom.Envelope lsBB = ls.getEnvelopeInternal();
-    double bbMinX = Math.max(realMinX, lsBB.getMinX());
-    double bbMinY = Math.max(realMinY, lsBB.getMinY());
-    double bbMaxX = Math.min(realMaxX, lsBB.getMaxX());
-    double bbMaxY = Math.min(realMaxY, lsBB.getMaxY());
-    int[] lsMinCell = convertRealToRaster(gc,bbMinX,bbMaxY);
-    int[] lsMaxCell = convertRealToRaster(gc,bbMaxX,bbMinY);
-
-    bbMinX = realMinX + lsMinCell[0] * cellWidth;
-    bbMaxX = realMinX + (lsMaxCell[0]+1) * cellWidth;
-    bbMinY = realMinY + (rasterHeight-(lsMaxCell[1]+1)) * cellHeight;
-    bbMaxY = realMinY + (rasterHeight-lsMinCell[1]) * cellHeight;
-
-    // Check all raster cells inside the BB of the LineString, whether they
-    // intersect the LineString
-    for (double y = bbMinY; y<=bbMaxY; y+=cellHeight)
-      for (double x = bbMinX; x<=bbMaxX; x+=cellWidth) {
-        cellBounds[0].x = x;
-        cellBounds[0].y = y;
-        cellBounds[1].x = x+cellWidth;
-        cellBounds[1].y = y;
-        cellBounds[2].x = x+cellWidth;
-        cellBounds[2].y = y+cellHeight;
-        cellBounds[3]   = cellBounds[0];
-        if ( ls.intersects(geomFac.createLinearRing(cellBounds)) ) {
-          int[] cell = convertRealToRaster(gc, x, y);
-          result.add( new Point(cell[0], cell[1]) );
-        }
-
-      }
-
-    return result;
-  }
-
-  /**
-   * Marks all raster cells, which are intersected by a {@link Geometry}.
-   * @param gc the raster
-   * @param g  Geometry, which is checked for intersection
-   * @param markValue value the intersected cells are marked with
-   * @param result Raster, the intersected cells are marked in (can be {@code null})
-   */
-  public static WritableRaster getOverlappingCells(GridCoverage2D gc, Geometry g, Number markValue, WritableRaster result) {
-    if ( result == null ) {
-      result = Raster.createWritableRaster(
-                     gc.getRenderedImage().getSampleModel(),
-                     new Point(
-                         gc.getRenderedImage().getMinX(),
-                         gc.getRenderedImage().getMinX()
-                     )
-      );
-    }
-
-    Envelope2D gridEnv      = gc.getEnvelope2D();
-    int        sampleType   = gc.getRenderedImage().getSampleModel().getDataType();
-    int        band         = 0;
-    double     realMinX     = gridEnv.getX();
-    double     realMinY     = gridEnv.getY();
-    double     realWidth    = gridEnv.getWidth();
-    double     realHeight   = gridEnv.getHeight();
-    double     realMaxX     = realMinX + realWidth;
-    double     realMaxY     = realMinY + realHeight;
-    int        rasterMinX   = gc.getRenderedImage().getMinX();
-    int        rasterMinY   = gc.getRenderedImage().getMinY();
-    int        rasterWidth  = gc.getRenderedImage().getWidth();
-    int        rasterHeight = gc.getRenderedImage().getHeight();
-    double     cellWidth    = realWidth / rasterWidth;
-    double     cellHeight   = realHeight / rasterHeight;
-
-
-    // Determine the raster cells inside the Geometry-BB
-    // -> only these are possibly intersected
-    com.vividsolutions.jts.geom.Envelope lsBB = g.getEnvelopeInternal();
-    double bbMinX = Math.max(realMinX, lsBB.getMinX());
-    double bbMinY = Math.max(realMinY, lsBB.getMinY());
-    double bbMaxX = Math.min(realMaxX, lsBB.getMaxX());
-    double bbMaxY = Math.min(realMaxY, lsBB.getMaxY());
-    int[] lsMinCell = convertRealToRaster(gc,bbMinX,bbMaxY);
-    int[] lsMaxCell = convertRealToRaster(gc,bbMaxX,bbMinY);
-
-    bbMinX = realMinX + lsMinCell[0] * cellWidth;
-    bbMaxX = realMinX + (lsMaxCell[0]+1) * cellWidth;
-    bbMinY = realMinY + (rasterHeight-(lsMaxCell[1]+1)) * cellHeight;
-    bbMaxY = realMinY + (rasterHeight-lsMinCell[1]) * cellHeight;
-
-    // Check all raster cells inside the BB of the Geometry, whether they
-    // really intersect the Geometry
-    Coordinate[]    cellBounds = new Coordinate[] { new Coordinate(), new Coordinate(), new Coordinate(), new Coordinate(), new Coordinate() };
-    GeometryFactory geomFac    = new GeometryFactory();
-    for (double y = bbMinY; y<=bbMaxY; y+=cellHeight)
-      for (double x = bbMinX; x<=bbMaxX; x+=cellWidth) {
-        cellBounds[0].x = x;
-        cellBounds[0].y = y;
-        cellBounds[1].x = x+cellWidth;
-        cellBounds[1].y = y;
-        cellBounds[2].x = x+cellWidth;
-        cellBounds[2].y = y+cellHeight;
-        cellBounds[3].x = x;
-        cellBounds[3].y = y+cellHeight;
-        cellBounds[4]   = cellBounds[0];
-        if ( g.intersects(geomFac.createLinearRing(cellBounds)) ) {
-          int[] cell = convertRealToRaster(gc, x, y);
-          switch ( sampleType ) {
-            case DataBuffer.TYPE_BYTE:
-            case DataBuffer.TYPE_SHORT:
-            case DataBuffer.TYPE_USHORT:
-            case DataBuffer.TYPE_INT:
-                        result.setSample(cell[0],cell[1],band,markValue.intValue());
-                        break;
-            case DataBuffer.TYPE_FLOAT:
-                        result.setSample(cell[0],cell[1],band,markValue.floatValue());
-                        break;
-            case DataBuffer.TYPE_DOUBLE:
-                        result.setSample(cell[0],cell[1],band,markValue.doubleValue());
-                        break;
-          }
-        }
-      }
-
-    return result;
-  }
-
-
-  /**
-   * Marks all raster cells, which are intersected by a {@link Geometry}.
-   * @param gc the raster
-   * @param g  Geometry, checked for intersection
-   * @param markValue value the intersected cells are marked with
-   * @return <b>a NEW instance of {@link GridCoverage2D}!!</b>
-   */
-  public static GridCoverage2D getOverlappingCells(GridCoverage2D gc, Geometry g, Number markValue) {
-    WritableRaster result = getOverlappingCells(gc,g,markValue,null);
-    return new GridCoverageFactory().create("",result,gc.getEnvelope());
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.grid;
+
+import java.awt.Color;
+import java.awt.Point;
+import java.awt.Rectangle;
+import java.awt.geom.Point2D;
+import java.awt.image.ComponentSampleModel;
+import java.awt.image.DataBuffer;
+import java.awt.image.Raster;
+import java.awt.image.RenderedImage;
+import java.awt.image.WritableRaster;
+import java.text.DecimalFormat;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Hashtable;
+import java.util.Map;
+import java.util.Set;
+
+import org.apache.log4j.Category;
+import org.apache.log4j.Logger;
+import org.geotools.coverage.FactoryFinder;
+import org.geotools.coverage.GridSampleDimension;
+import org.geotools.coverage.grid.GridCoverage2D;
+import org.geotools.coverage.grid.GridCoverageFactory;
+import org.geotools.coverage.grid.GridGeometry2D;
+import org.geotools.geometry.Envelope2D;
+import org.geotools.styling.ColorMap;
+import org.geotools.styling.RasterSymbolizer;
+import org.geotools.styling.Style;
+import org.geotools.styling.StyleBuilder;
+import org.opengis.coverage.PointOutsideCoverageException;
+import org.opengis.coverage.SampleDimension;
+import org.opengis.coverage.grid.GridRange;
+import org.opengis.geometry.Envelope;
+
+import schmitzm.data.WritableGrid;
+import schmitzm.data.WritableGridArray;
+import schmitzm.geotools.GTUtil;
+import schmitzm.geotools.styling.StylingUtil;
+import schmitzm.lang.LangUtil;
+import schmitzm.swing.SwingUtil;
+
+import com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.Geometry;
+import com.vividsolutions.jts.geom.GeometryFactory;
+import com.vividsolutions.jts.geom.LineString;
+
+/**
+ * Diese Klasse stellt statische Funktionen fuer die Arbeit mit
+ * {@linkplain GridCoverage2D Rasterdaten} zur Verfuegung.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.01
+ */
+public class GridUtil {
+
+        /** log4j initialize */
+        private static final Category cCat = Logger.getLogger(GridUtil.class.getName());
+
+      public static final GridCoverageFactory GRID_FAC = new GridCoverageFactory();
+
+	/**
+	 * The default name for style created by createDefaultStyle();
+	 */
+	  public static final String DEFAULT_RASTER_STYLE_NAME = "default raster style";
+	  public static final String DEFAULT_RASTER_STYLE_TITLE = "default raster style";
+	  public static final String UNNAMED_RASTER_STYLE_NAME = "unnamed raster style";
+	  public static final String UNTITLED_RASTER_STYLE_TITLE = "untitled raster style";
+
+	  /**
+	   * 11 Default colors used by {@link #createDiscreteStyle(GridCoverage2D, double, Color...)} if
+	   * no colors are given.
+	   * <ol>
+	   *   <li>White</li>
+	   *   <li>Red</li>
+	   *   <li>Blue</li>
+	   *   <li>Yellow</li>
+	   *   <li>Green</li>
+	   *   <li>Gray</li>
+	   *   <li>Orange</li>
+	   *   <li>Pink</li>
+	   *   <li>Magenta</li>
+       *   <li>Light gray</li>
+	   *   <li>Cyan</li>
+	   *   <li>Black</li>
+	   * </ol>
+	   */
+      public static final Color[] DEFAULT_COLORS = new Color[] {
+          Color.WHITE,
+          Color.RED,
+          Color.BLUE,
+          Color.YELLOW,
+          Color.GREEN,
+          Color.GRAY,
+          Color.ORANGE,
+          Color.PINK,
+          Color.MAGENTA,
+          Color.LIGHT_GRAY,
+          Color.CYAN,
+          Color.BLACK
+      };
+
+
+      /**
+	   * Liefert statistische Daten ueber ein Grid und erstellt ein Histogramm
+	   * @param gc ein Raster
+	   * @param band zu untersuchendes Band
+	   * @param histogramSteps Schritte des Histogramms, -1 wenn alle Ausprägungen, 0 für ohne Histogramm
+	   * @param histogrammDigits Anzahl an Nachkommastellen auf die die Histogramm-Klassen gerundet werden
+	   *                         (negative Werte = Vorkommastellen; null = kein Runden). Nur relevant, wenn
+	   *                         {@code hishistogramSteps} = -1
+	   * @author Martin Schmitz
+	   * @author Andreas Enders
+	   */
+	  public static GridStatistic determineStatistic(GridCoverage2D gc, int band, int histogramSteps, Integer histogrammDigits) {
+	    GridStatistic gs = new GridStatistic();
+	    GridRange     gr = gc.getGridGeometry().getGridRange();
+	    Envelope2D    ev = gc.getEnvelope2D();
+	    gs.minX          = gr.getLower(0);
+	    gs.minY          = gr.getLower(1);
+	    gs.maxX          = gr.getUpper(0);
+	    gs.maxY          = gr.getUpper(1);
+	    gs.widthC        = gs.maxX - gs.minX;
+	    gs.heightC       = gs.maxY - gs.minY;
+	    gs.widthR        = ev.getLength(0);
+	    gs.heightR       = ev.getLength(1);
+	    gs.latSW         = ev.getX();
+	    gs.lonSW         = ev.getY();
+	    gs.cellWidth     = (gs.widthC != 0) ? gs.widthR / gs.widthC : 0;
+	    gs.cellHeight    = (gs.heightC != 0) ? gs.heightR / gs.heightC : 0;
+
+	    gs.nodataCnt     = 0;
+	    gs.cellCnt       = 0;
+	    gs.noDataVal     = gc.getSampleDimensions()[band].getNoDataValues();
+	    if ( gs.noDataVal == null )
+	      gs.noDataVal = new double[0];
+	    gs.sumValue      = 0;
+
+
+	    // Check auf NoData-Zellen erfolgt ueber Hash-Tabelle
+	    Hashtable isNoData = new Hashtable<Double,Boolean>(gs.noDataVal.length);
+	    for (int i=0; i<gs.noDataVal.length; i++)
+	      isNoData.put(gs.noDataVal[i],true);
+
+	    // Objekte fuer Koordinate
+	    Point2D  p        = new Point2D.Float();
+	    double[] val      = new double[ gc.getSampleDimensions().length ];
+
+	    double lon = gs.lonSW + gs.cellHeight/2;
+	    for (int y=gs.minY; y<gs.maxY; y++, lon+=gs.cellHeight) {
+	      double lat = gs.latSW + gs.cellWidth/2;
+	      for (int x=gs.minX; x<gs.maxX; x++, lat+=gs.cellWidth) {
+	        p.setLocation(lat,lon);
+	        gc.evaluate(p,val);
+	        // NoData-Zellen gehen nicht in die Statistik ein
+	        if ( Double.isNaN(val[band]) || isNoData.containsKey(val[band]) )
+	          gs.nodataCnt++;
+	        else {
+	          gs.minValue = Math.min(gs.minValue, val[band]);
+	          gs.maxValue = Math.max(gs.maxValue, val[band]);
+	          gs.sumValue += val[band];
+	          gs.cellCnt++;
+	        }
+	      }
+	    }
+	    //histogramm berechnen, wenn nicht ausgeschaltet
+	    if (histogramSteps != 0)
+	    {
+	      lon = gs.lonSW + gs.cellHeight/2;
+	      for (int y=gs.minY; y<gs.maxY; y++, lon+=gs.cellHeight)
+	      {
+	        double lat = gs.latSW + gs.cellWidth/2;
+	        for (int x=gs.minX; x<gs.maxX; x++, lat+=gs.cellWidth)
+	        {
+	          p.setLocation(lat,lon);
+	          gc.evaluate(p,val);
+	          // NoData-Zellen gehen nicht in die Statistik ein
+	          if ( !Double.isNaN(val[band]) && !isNoData.containsKey(val[band]) )
+	          {
+	            double tVal = val[band];
+	            if (histogramSteps < 0)
+	            {
+	              //String tValue = ""+(new Double(tVal).longValue());
+	              String value = String.valueOf( histogrammDigits != null ? LangUtil.round(tVal,histogrammDigits) : tVal );
+	              Integer pixelCount = gs.histogramm.get(value);
+	              if (pixelCount == null)
+	                pixelCount = 1;
+	              else
+	                pixelCount++;
+	              gs.histogramm.put(value, pixelCount);
+	            }
+	            else
+	            {
+	              double stepRange = (gs.maxValue - gs.minValue)/histogramSteps;
+	              int step = new Double((tVal - gs.minValue)/stepRange).intValue();
+	              String stepName = ""+gs.minValue + step * stepRange;
+	              Integer number = gs.histogramm.get(stepName);
+	              if (number == null) number = 1;
+	              else number++;
+	              gs.histogramm.put(stepName, number);
+	            }
+	          }
+	        }
+	      }
+              cCat.debug("Histogram created with map: "+gs.histogramm);
+	    }
+	    // Durchschnittswert berechnen (nicht ueber NoData-Zellen)
+	    gs.avgValue = (gs.cellCnt != 0) ? gs.sumValue/gs.cellCnt : 0;
+
+	    return gs;
+	  }
+
+
+      /**
+       * Liefert statistische Daten ueber ein Grid und erstellt ein Histogramm.
+       * Die Histogramm-Klassen werden auf ganze Zahlen gerundet.
+       * @param gc ein Raster
+       * @param band zu untersuchendes Band
+       * @param histogramSteps Schritte des Histogramms, -1 wenn alle Ausprägungen, 0 für ohne Histogramm
+       * @author Martin Schmitz
+       * @author Andreas Enders
+       */
+      public static GridStatistic determineStatistic(GridCoverage2D gc, int band, int histogramSteps) {
+        return determineStatistic(gc, band, histogramSteps, 0);
+      }
+
+  /**
+   * Liefert statistische Daten ueber ein Grid, ohne ein Histogram zu berechnen.
+   * @param gc ein Raster
+   * @param band zu untersuchendes Band
+   */
+  public static GridStatistic determineStatistic(GridCoverage2D gc, int band) {
+	  return determineStatistic(gc, band, 0);
+  }
+
+  /**
+   * Liefert statistische Daten ueber ein Grid, das in Zonen unterteilt ist.
+   * Die Zonen werden durch einen {@link Float}-Wert identifiziert, damit
+   * auch NoData-Werte in einem Raster einer Zone (naemlich der
+   * Zone {@code Float.NaN}) zugewiesen werden koennen.
+   * @param valueGC Raster ueber das die Statistik erzeugt wird
+   * @param zoneGC Raster, das die Zonen bestimmt
+   */
+  public static GridZoneStatistic<Float> determineZoneStatistic(GridCoverage2D valueGC, GridCoverage2D zoneGC) {
+    return determineZoneStatistic(valueGC, 0, zoneGC, 0);
+  }
+
+  /**
+   * Liefert statistische Daten ueber ein Grid, das in Zonen unterteilt ist.
+   * Die Zonen werden durch einen {@link Float}-Wert identifiziert, damit
+   * auch NoData-Werte in einem Raster einer Zone (naemlich der
+   * Zone {@code Float.NaN}) zugewiesen werden koennen.
+   * @param valueGC Raster ueber das die Statistik erzeugt wird
+   * @param valueBand Band ueber das die Statistik erzeugt wird
+   * @param zoneGC Raster, das die Zonen bestimmt
+   * @param zoneBand Band, das die Zonen bestimmt
+   */
+  public static GridZoneStatistic<Float> determineZoneStatistic(GridCoverage2D valueGC, int valueBand, GridCoverage2D zoneGC, int zoneBand) {
+    final ReadableGridCoverage zoneGrid  = ReadableGridCoverage.create(zoneGC, 0);
+
+    // Performanz: Raster-Ausmasse in lokalen Variablen speichern
+    final float         cellHeight = (float)zoneGrid.getCellHeight();
+    final float         cellWidth  = (float)zoneGrid.getCellHeight();
+    final float         minX       = (float)zoneGrid.getX() + cellWidth/2;
+    final float         maxX       = (float)(zoneGrid.getX() + zoneGrid.getRealWidth());
+    final float         minY       = (float)zoneGrid.getY() + cellHeight/2;
+    final float         maxY       = (float)(zoneGrid.getY() + zoneGrid.getRealHeight());
+
+//    // Solution without WritableGrid
+//    final Envelope2D    env        = zoneGC.getEnvelope2D();
+//    final GridRange     gr         = zoneGC.getGridGeometry().getGridRange();
+//    final float         height     = (float)env.getHeight();
+//    final float         width      = (float)env.getWidth();
+//    final int           heightC    = Math.abs( gr.getLower(1) - gr.getUpper(1) );
+//    final int           widthC     = Math.abs( gr.getLower(0) - gr.getUpper(0) );
+//    final float         cellHeight = heightC != 0 ? height / heightC : 0;
+//    final float         cellWidth  = widthC  != 0 ? width  / widthC  : 0;
+//    final float         minX       = (float)env.getX() + cellWidth/2;
+//    final float         maxX       = (float)(env.getX() + width);
+//    final float         minY       = (float)env.getY() + cellHeight/2;
+//    final float         maxY       = (float)(env.getY() + height);
+
+    final Point2D.Float loc        = new Point2D.Float();
+    // Arrays zum Speichern der Rasterwerte pro Band
+    final float[]  zoneGridVal  = new float[zoneGC.getNumSampleDimensions()];
+    final float[]  valueGridVal = new float[zoneGC.getNumSampleDimensions()];
+    // Variablen zum Speichern des Band-Werts
+    float zoneNo  = 0;
+    float cellVal = 0;
+
+    // Zonen-Statistik berechnen
+    GridZoneStatistic    zoneStat  = new GridZoneStatistic<Float>();
+    for (loc.y=minY; loc.y<maxY; loc.y+=cellHeight)
+      for (loc.x=minX; loc.x<=maxX; loc.x+=cellWidth) {
+        zoneGC.evaluate(loc, zoneGridVal);
+        zoneNo = zoneGridVal[zoneBand];
+        try {
+          valueGC.evaluate(loc, valueGridVal);
+          cellVal = valueGridVal[valueBand];
+          zoneStat.addValueToZoneStatistic(zoneNo, cellVal);
+        } catch (PointOutsideCoverageException err) {
+          // Zonen-Zelle liegt ausserhalb des Wert-Rasters
+          // --> Zelle ignorieren
+        }
+      }
+
+    return zoneStat;
+  }
+
+  /**
+   * Erzeugt einen Standard-Style fuer ein {@link GridCoverage2D}
+   * und setzt den default-Namen: GridUtil.DEFAULT_RASTER_STYLE_NAME
+   * Und eine title : GridUtil.DEFAULT_RASTER_STYLE_TITLE
+   *
+   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+   * @author Stefan Alfons Krüger (DEFAULT_RASTER_STYLE_NAME, DEFAULT_RASTER_STYLE_TITLE)
+   */
+  public static Style createDefaultStyle() {
+    Style defaultStyle = createStyle(null,1.0);
+    defaultStyle.setName(DEFAULT_RASTER_STYLE_NAME);
+    defaultStyle.setTitle(DEFAULT_RASTER_STYLE_TITLE);
+	return( defaultStyle );
+  }
+
+  /**
+   * Erzeugt einen Standard-Style fuer ein {@link GridCoverage2D}
+   * @param colorMap Farb-Palette
+   * @param opacity  Transparenz (1.0 = vollfarbig)
+   * @return ein Standard-Style ( {@code StyleBuilder.createRasterSymbolizer()}) falls
+   *         keine ColorMap angegeben wird
+   */
+  public static Style createStyle(ColorMap colorMap, double opacity) {
+    StyleBuilder builder = StylingUtil.STYLE_BUILDER;
+    RasterSymbolizer symb = colorMap != null ? builder.createRasterSymbolizer(colorMap,opacity) : builder.createRasterSymbolizer();
+    return( builder.createStyle( symb ) );
+  }
+
+  /**
+   * Creates an interpolative style for a {@link GridCoverage2D}. The given colors
+   * are interpolated from the minimum to the maximum raster value.
+   * @param grid     the raster
+   * @param opacity  opacity for the style
+   * @param colors   colors to interpolate with (at least 2)
+   */
+  public static Style createInterpolativeStyle(GridCoverage2D grid, double opacity, Color... colors) {
+    if ( colors.length < 2 )
+      throw new IllegalArgumentException("At least 2 colors must be specified for an interpolative style.");
+    GridStatistic gridStat  = GridUtil.determineStatistic(grid, 0);
+    double   intervalLength = gridStat.maxValue - gridStat.minValue;
+    String[] labels         = new String[colors.length];
+    double[] values         = new double[colors.length];
+    for (int i=0; i<colors.length; i++) {
+      labels[i] = ""; // all categories must have the same label
+      values[i] = gridStat.minValue + intervalLength * i/(colors.length-1.0);
+    }
+    ColorMap colorMap = StylingUtil.STYLE_BUILDER.createColorMap(
+        labels,
+        values,
+        colors,
+        ColorMap.TYPE_RAMP
+    );
+    RasterSymbolizer rasterSymb = StylingUtil.STYLE_BUILDER.createRasterSymbolizer(colorMap, opacity);
+    return StylingUtil.STYLE_BUILDER.createStyle( rasterSymb );
+  }
+
+  /**
+   * Creates a discrete style for a {@link GridCoverage2D}. For every value
+   * in the raster another color is choosen. If the raster contains more values
+   * than colors are given, all surplus values are mapped to the "last" color.
+   * @param grid          the raster
+   * @param opacity       opacity for the style
+   * @param digits        number of digits the grid value classes (and legend) are
+   *                      rounded to (null means no round; >= 0 means digits after comma;
+   *                      < 0 means digits before comma)
+   * @param colorPalette  colors for the values (the smallest value is mapped to index 0, the second
+   *                      smallest to index 1, ...); if no colors are specified {@link #DEFAULT_COLORS}
+   *                      are used
+   */
+  public static Style createDiscreteStyle(GridCoverage2D grid, double opacity, Integer digits, Color... colorPalette) {
+    if ( colorPalette.length == 0 )
+      colorPalette = DEFAULT_COLORS;
+    DecimalFormat decFormat = digits != null ? new DecimalFormat( SwingUtil.getNumberFormatPattern(digits) ) : null;
+    GridStatistic gridStat  = GridUtil.determineStatistic(grid, 0, -1, digits);
+
+    int      valueCount = gridStat.histogramm.size();
+    String[] labels     = new String[valueCount];
+    double[] values     = new double[valueCount];
+    Color[]  colors     = new Color[valueCount];
+    Color    lastColor  = colorPalette[colorPalette.length-1];
+
+    int i = -1;
+    for (String key : gridStat.histogramm.keySet()) {
+      i++;
+      values[i] = Double.parseDouble(key);
+      colors[i] = i < colorPalette.length ? colorPalette[i] : lastColor;
+      if ( decFormat != null )
+        labels[i] = decFormat.format(values[i]);
+      else
+        labels[i] = String.valueOf(values[i]);
+      //labels[i] += " ("+gridStat.histogramm.get(key)+" pixel)";
+    }
+
+    ColorMap tColorMap = StylingUtil.STYLE_BUILDER.createColorMap(
+        labels,
+        values,
+        colors,
+        ColorMap.TYPE_VALUES
+    );
+
+    RasterSymbolizer rasterSymb = StylingUtil.STYLE_BUILDER.createRasterSymbolizer(tColorMap, opacity);
+    return StylingUtil.STYLE_BUILDER.createStyle( rasterSymb );
+  }
+
+  /**
+   * Kopiert ein {@link GridCoverage2D} komplett.
+   * @param source Quell-Raster
+   */
+  public static GridCoverage2D copyGridCoverage(GridCoverage2D source) {
+    //return createGridCoverage(source,source.getEnvelope());
+    return GRID_FAC.create(
+        source.getName(),
+        source.getRenderedImage().copyData(null),
+        source.getEnvelope()
+    );
+  }
+
+  /**
+   * Kopiert ein {@link GridCoverage2D} komplett, dessen Raster-Koordinaten
+   * (obere-linke Ecke) transformiert wird.
+   * @param source Quell-Raster
+   * @param minX   neue Raster-Koordinate fuer die obere linke Ecke
+   * @param minY   neue Raster-Koordinate fuer die obere linke Ecke
+   */
+  public static GridCoverage2D copyGridCoverage(GridCoverage2D source, int minX, int minY) {
+    return GRID_FAC.create(
+                      source.getName(),
+                      source.getRenderedImage().copyData(null).createWritableTranslatedChild(minX, minY),
+                      source.getEnvelope()
+           );
+  }
+
+  /**
+   * Erzeugt ein neues {@link GridCoverage2D} mit neuer {@link SampleDimension}.
+   * @param gc        Raster (mit nur einem Band)
+   * @param sampleDim neue {@link SampleDimension}
+   * @return eine neue {@link GridCoverage2D}-Instanz
+   */
+  public static GridCoverage2D resampleGridCoverage(GridCoverage2D gc, GridSampleDimension sampleDim) {
+    return resampleGridCoverage(gc, new GridSampleDimension[] {sampleDim});
+  }
+
+  /**
+   * Erzeugt ein neues {@link GridCoverage2D} mit neuer {@link SampleDimension}.
+   * @param gc        Raster
+   * @param sampleDim neue {@link SampleDimension}
+   * @return eine neue {@link GridCoverage2D}-Instanz
+   */
+  public static GridCoverage2D resampleGridCoverage(GridCoverage2D gc, GridSampleDimension[] sampleDim) {
+    final Map properties = new HashMap();
+    //  properties.put("GC_NODATA", -9999.0);
+
+    return FactoryFinder.getGridCoverageFactory(null).create(
+        gc.getName(),
+        gc.getRenderedImage(),
+        (GridGeometry2D)gc.getGridGeometry(),
+        sampleDim,
+        null, //new GridCoverage[] { raster },
+        properties
+    );
+  }
+
+  /**
+   * Erzeugt ein {@link GridCoverage2D} aus einem anderen. Das neue Raster
+   * hat maximal die Ausmasse des Quell-Rasters.
+   * @param source Quell-Raster
+   * @param bboxEnv Bounding-Box (beschreibt die den Ausschnitt des Quell-Rasters aus dem
+   *                das neue Raster erzeugt wird)
+   * @return {@code null} falls sich das Quell-Raster und die Bounding-Box nicht
+   *         ueberschneiden.
+   */
+  public static GridCoverage2D createGridCoverage(GridCoverage2D source, Envelope bboxEnv) {
+    Envelope2D sourceEnv = source.getEnvelope2D();
+    // Subset nur bzgl. des Bereichs in dem auch das Raster liegt
+    bboxEnv = GTUtil.intersectEnvelope(sourceEnv,bboxEnv,source.getCoordinateReferenceSystem());
+    if ( bboxEnv.getLength(0) == 0 && bboxEnv.getLength(1) == 0 )
+      return null;
+
+    // Daten des Source-Raster
+    double realMinX     = sourceEnv.getX();
+    double realMinY     = sourceEnv.getY();
+    double realWidth    = sourceEnv.getWidth();
+    double realHeight   = sourceEnv.getHeight();
+    int    rasterMinX   = source.getRenderedImage().getMinX();
+    int    rasterMinY   = source.getRenderedImage().getMinY();
+    int    rasterWidth  = source.getRenderedImage().getWidth();
+    int    rasterHeight = source.getRenderedImage().getHeight();
+    double cellWidth    = realWidth / rasterWidth;
+    double cellHeight   = realHeight / rasterHeight;
+
+    // Envelope in Raster-Koordinaten (bzgl. unterer linker Ecke!)
+    int subsetLX = convertRealToRaster(bboxEnv.getLowerCorner().getOrdinate(0),realMinX,realWidth,rasterMinX,rasterWidth);
+    int subsetLY = convertRealToRaster(bboxEnv.getLowerCorner().getOrdinate(1),realMinY,realHeight,rasterMinY,rasterHeight);
+    int subsetUX = convertRealToRaster(bboxEnv.getUpperCorner().getOrdinate(0),realMinX,realWidth,rasterMinX,rasterWidth);
+    int subsetUY = convertRealToRaster(bboxEnv.getUpperCorner().getOrdinate(1),realMinY,realHeight,rasterMinY,rasterHeight);
+    int subsetW  = Math.abs(subsetLX-subsetUX)+1;
+    int subsetH  = Math.abs(subsetLY-subsetUY)+1;
+    // obere linke Ecke des Subsets in Raster-Koordinaten
+    int ulX = Math.min(subsetLX,subsetUX);
+    int ulY = rasterMinY+rasterHeight - Math.max(subsetLY,subsetUY) -1;
+
+    // WritableRaster fuer Subset erstellen
+    Rectangle       rect = new Rectangle(ulX,ulY,subsetW,subsetH);
+    Raster          r    = source.getRenderedImage().getData( rect );
+    WritableRaster  wr   = createWritableRaster(r);
+
+    // Envelope fuer Subset erzeugen (bzgl. untere liner Ecke!)
+    Envelope subsetEnv = new Envelope2D(
+        source.getCoordinateReferenceSystem(),
+        convertRasterToReal(subsetLX,rasterMinX,realMinX,cellWidth)-cellWidth/2,
+        convertRasterToReal(subsetLY,rasterMinY,realMinY,cellHeight)-cellHeight/2,
+        subsetW * cellWidth,
+        subsetH * cellHeight
+    );
+
+    return new GridCoverageFactory().create("",wr,subsetEnv);
+  }
+
+
+  /**
+   * Erzeugt ein {@link WritableRaster} aus einem {@link Raster}.
+   * @param r Raster
+   * @param minX Start-Index in X-Richtung
+   * @param minY Start-Index in Y-Richtung
+   */
+  public static WritableRaster createWritableRaster(Raster r, int minX, int minY) {
+    return Raster.createWritableRaster(
+        new ComponentSampleModel(r.getDataBuffer().getDataType(),
+                                 r.getWidth(),
+                                 r.getHeight(),
+                                 1,
+                                 r.getWidth(),
+                                 new int[] {0}),
+        r.getDataBuffer(),
+        new Point(minX,minY)
+    );
+  }
+
+  /**
+   * Erzeugt ein {@link WritableRaster} aus einem {@link Raster}.
+   * @param r Raster
+   */
+  public static WritableRaster createWritableRaster(Raster r) {
+    return createWritableRaster(r,0,0);
+  }
+ 
+  /**
+   * Konvertiert ein Raster-Objekt in eine {@link GridCoverage2D}.
+   * Es werden folgende Objekt-Typen unterstuetzt:
+   * <ul>
+   *   <li>Instanzen von {@link GridCoverage2D}</li>
+   *   <li>Instanzen von {@link WritableRaster} <u>und</u> {@link WritableGrid}</li>
+   *   <li>Instanzen von {@link WritableGridArray}</li>
+   * </ul>
+   * @param obj Object
+   * @exception IllegalArgumentException falls das Objekt nicht konvertiert werden kann
+   */
+  public static GridCoverage2D convertToGridCoverage2D(Object obj) {
+    if ( obj instanceof GridCoverage2D )
+      return (GridCoverage2D)obj;
+
+    if ( obj instanceof WritableRaster  && obj instanceof WritableGrid ) {
+      // GT-GridCoverage aus WritableGridRaster erzeugen
+      WritableRaster wr = (WritableRaster)obj;
+      WritableGrid   wg = (WritableGrid)obj;
+      Envelope2D     ev = new Envelope2D(wg.getCoordinateReferenceSystem(),wg.getX(),wg.getY(),wg.getRealWidth(),wg.getRealHeight());
+      return new GridCoverageFactory().create("",wr,ev);
+    }
+
+    if ( obj instanceof WritableGridArray ) {
+      // GT-GridCoverage aus WritableGridRaster erzeugen
+      WritableGridArray wga = (WritableGridArray)obj;
+      Envelope2D        ev = GTUtil.createEnvelope2D(wga.getEnvelope(),wga.getCoordinateReferenceSystem());
+      WritableRaster    wr = Raster.createWritableRaster(
+          new ComponentSampleModel(wga.getSampleType(),
+                                   wga.getWidth(),
+                                   wga.getHeight(),
+                                   1,
+                                   wga.getWidth(),
+                                   new int[] {0}
+          ),
+          wga.getDataBuffer(),
+          new Point(0,0)
+      );
+      return new GridCoverageFactory().create("",wr,ev);
+    }
+
+    throw new IllegalArgumentException("Object can not be converted to GridCoverage2D: "+(obj==null ? "null" : obj.getClass().getSimpleName()));
+
+  }
+
+
+  /**
+   * Converts a real world coordinate to the row/column number of a raster.
+   * If the coordinate value is exactly located on the border between two
+   * cells, the next greater raster cell is returned (except the raster border:
+   * the lower (=last) cell is returned).<br>
+   * This method can be applied on all dimensions (X or Y or ...), if the
+   * accordingly input parameter for the dimension are given.<br>
+   * <b>Note:</b>
+   * Because this method is independed from the dimension, it assumes that the
+   * "beginning" of the raster coordinates is located in the same corner like
+   * the lat/lon-refernce!! 
+   * @param coord        geographic reference (world coordinate), which is converted
+   * @param realMin      minimal world coordinate of the raster
+   * @param realLength   length of the raster in "world coordinates"
+   * @param rasterMin    index of the first raster cell (normally 0)
+   * @param rasterLength size of the raster (in cells)
+   * @exception UnsupportedOperationException falls als {@code rasterLength} 0
+   *            uebergeben wird
+   */
+  public static int convertRealToRaster(final double coord, final double realMin, final double realLength, final int rasterMin, final int rasterLength) {
+    if ( rasterLength <= 0 )
+      throw new UnsupportedOperationException("Length of raster must be > 0!");
+    final double cellSize = realLength / rasterLength;
+
+    // Wenn Koordinate genau den Rasterrand trifft, wird die letzte
+    // Zelle zurueckgegeben...
+    if ( coord == realMin + realLength )
+      return rasterMin + rasterLength - 1;
+    // ... sonst die naechste Zelle
+    // Bemerkung: Einfaches Abschneiden (int) reicht nicht, es muss die
+    //            naechstkleinere Zahl ermittelt werden, denn sonst gibt
+    //            es die Zelle 0 zweimal, z.B.
+    //              (coord-realMin)/cellSize =  0.8 --> Zelle 0 (korrekt)
+    //              (coord-realMin)/cellSize = -0.8 --> Zelle 0 (falsch)
+    //            Im zweiten Fall muss auf -1 "gerundet" werden!
+    return ((int)Math.floor( (coord-realMin) / cellSize ) ) + rasterMin;
+  }
+
+  /**
+   * Converts a raster cell index to "real" world coordinates. The coordinate
+   * of the cell center is returned.<br> 
+   * This method can be applied on all dimensions (X or Y or ...), if the
+   * accordingly input parameter for the dimension are given.<br>
+   * <b>Note:</b>
+   * Because this method is independed from the dimension, it assumes that the
+   * "beginning" of the raster coordinates is located in the same corner like
+   * the lat/lon-refernce!! 
+   * @param cell       raster index, which is converted
+   * @param rasterMin  minimal index of the raster
+   * @param realMin    minimal world coordinate of the raster
+   * @param cellSize   size of one cell in "world coordinates"
+   */
+  public static double convertRasterToReal(final int cell, final int rasterMin, final double realMin, final double cellSize) {
+    return realMin + (cell-rasterMin)*cellSize + 0.5*cellSize;
+  }
+
+  /**
+   * Converts a geo reference to raster coordinates.
+   * @param gc   source raster
+   * @param geoX Longitude to be converted
+   * @param geoY Latitude to be converted
+   * @return 2-dimensional array with the X-index in element 0 and the Y-index in
+   *         element 1
+   */
+  public static int[] convertRealToRaster(GridCoverage2D gc, double geoX, double geoY) {
+    return convertRealToRaster(gc, new double[] { geoX, geoY } );
+  }
+
+  /**
+   * Converts a geo reference to raster coordinates.
+   * @param env      geo reference of the raster
+   * @param image    image of the raster
+   * @param geoX     Longitude to be converted
+   * @param geoY     Latitude to be converted
+   * @return 2-dimensional array with the X-index in element 0 and the Y-index in
+   *         element 1
+   */
+  public static int[] convertRealToRaster(Envelope2D env, RenderedImage image, double geoX, double geoY) {
+    return convertRealToRaster(env, image, new double[] { geoX, geoY } );
+  }
+
+  /**
+   * Converts a geo reference to raster coordinates.
+   * @param gc   source raster
+   * @param geoCoord geo reference (Longitude,Latitude) to be converted
+   * @return 2-dimensional array with the X-index in element 0 and the Y-index in
+   *         element 1
+   */
+  public static int[] convertRealToRaster(GridCoverage2D gc, double[] geoCoord) {
+    return convertRealToRaster(gc.getEnvelope2D(), gc.getRenderedImage(), geoCoord);
+  }
+
+  /**
+   * Converts a geo reference to raster coordinates.
+   * @param env      geo reference of the raster
+   * @param image    image of the raster
+   * @param geoCoord geo reference (Longitude,Latitude) to be converted
+   * @return 2-dimensional array with the X-index in element 0 and the Y-index in
+   *         element 1
+   */
+  public static int[] convertRealToRaster(Envelope2D env, RenderedImage image, double[] geoCoord) {
+    final double realMinX = env.getX();
+    final double realMinY = env.getY();
+    final double realWidth = env.getWidth();
+    final double realHeight = env.getHeight();
+    final int    rasterMinX = image.getMinX();
+    final int    rasterMinY = image.getMinY();
+    final int    rasterWidth = image.getWidth();
+    final int    rasterHeight = image.getHeight();
+
+    int cellX = convertRealToRaster(geoCoord[0],realMinX,realWidth,rasterMinX,rasterWidth);
+    int cellY = convertRealToRaster(geoCoord[1],realMinY,realHeight,rasterMinY,rasterHeight);
+    // Ursprung der Raster-Koord. ist OBEN LINKS
+    cellY = rasterMinY+rasterHeight - cellY - 1;
+
+    return new int[] {cellX, cellY};
+  }
+
+
+  /**
+   * Determines the raster cells, which are intersected by a {@link LineString}.
+   * @param gc the raster
+   * @param ls {@link LineString} to check
+   * @param result Set the intersected cells are inserted in (can be {@code null})
+   * @return an empty set if the LineString is located outside the raster
+   */
+  public static Set<Point> getOverlappingCells(GridCoverage2D gc, LineString ls, Set<Point> result) {
+    if ( result == null )
+      result = new HashSet<Point>();
+
+    Envelope2D gridEnv      = gc.getEnvelope2D();
+    double     realMinX     = gridEnv.getX();
+    double     realMinY     = gridEnv.getY();
+    double     realWidth    = gridEnv.getWidth();
+    double     realHeight   = gridEnv.getHeight();
+    double     realMaxX     = realMinX + realWidth;
+    double     realMaxY     = realMinY + realHeight;
+    int        rasterMinX   = gc.getRenderedImage().getMinX();
+    int        rasterMinY   = gc.getRenderedImage().getMinY();
+    int        rasterWidth  = gc.getRenderedImage().getWidth();
+    int        rasterHeight = gc.getRenderedImage().getHeight();
+    double     cellWidth    = realWidth / rasterWidth;
+    double     cellHeight   = realHeight / rasterHeight;
+
+    Coordinate[]    cellBounds = new Coordinate[] { new Coordinate(), new Coordinate(), new Coordinate(), new Coordinate() };
+    GeometryFactory geomFac    = new GeometryFactory();
+
+    // determine the cells of the LineStrings start/end point
+    com.vividsolutions.jts.geom.Envelope lsBB = ls.getEnvelopeInternal();
+    double bbMinX = Math.max(realMinX, lsBB.getMinX());
+    double bbMinY = Math.max(realMinY, lsBB.getMinY());
+    double bbMaxX = Math.min(realMaxX, lsBB.getMaxX());
+    double bbMaxY = Math.min(realMaxY, lsBB.getMaxY());
+    int[] lsMinCell = convertRealToRaster(gc,bbMinX,bbMaxY);
+    int[] lsMaxCell = convertRealToRaster(gc,bbMaxX,bbMinY);
+
+    bbMinX = realMinX + lsMinCell[0] * cellWidth;
+    bbMaxX = realMinX + (lsMaxCell[0]+1) * cellWidth;
+    bbMinY = realMinY + (rasterHeight-(lsMaxCell[1]+1)) * cellHeight;
+    bbMaxY = realMinY + (rasterHeight-lsMinCell[1]) * cellHeight;
+
+    // Check all raster cells inside the BB of the LineString, whether they
+    // intersect the LineString
+    for (double y = bbMinY; y<=bbMaxY; y+=cellHeight)
+      for (double x = bbMinX; x<=bbMaxX; x+=cellWidth) {
+        cellBounds[0].x = x;
+        cellBounds[0].y = y;
+        cellBounds[1].x = x+cellWidth;
+        cellBounds[1].y = y;
+        cellBounds[2].x = x+cellWidth;
+        cellBounds[2].y = y+cellHeight;
+        cellBounds[3]   = cellBounds[0];
+        if ( ls.intersects(geomFac.createLinearRing(cellBounds)) ) {
+          int[] cell = convertRealToRaster(gc, x, y);
+          result.add( new Point(cell[0], cell[1]) );
+        }
+
+      }
+
+    return result;
+  }
+
+  /**
+   * Marks all raster cells, which are intersected by a {@link Geometry}.
+   * @param gc the raster
+   * @param g  Geometry, which is checked for intersection
+   * @param markValue value the intersected cells are marked with
+   * @param result Raster, the intersected cells are marked in (can be {@code null})
+   */
+  public static WritableRaster getOverlappingCells(GridCoverage2D gc, Geometry g, Number markValue, WritableRaster result) {
+    if ( result == null ) {
+      result = Raster.createWritableRaster(
+                     gc.getRenderedImage().getSampleModel(),
+                     new Point(
+                         gc.getRenderedImage().getMinX(),
+                         gc.getRenderedImage().getMinX()
+                     )
+      );
+    }
+
+    Envelope2D gridEnv      = gc.getEnvelope2D();
+    int        sampleType   = gc.getRenderedImage().getSampleModel().getDataType();
+    int        band         = 0;
+    double     realMinX     = gridEnv.getX();
+    double     realMinY     = gridEnv.getY();
+    double     realWidth    = gridEnv.getWidth();
+    double     realHeight   = gridEnv.getHeight();
+    double     realMaxX     = realMinX + realWidth;
+    double     realMaxY     = realMinY + realHeight;
+    int        rasterMinX   = gc.getRenderedImage().getMinX();
+    int        rasterMinY   = gc.getRenderedImage().getMinY();
+    int        rasterWidth  = gc.getRenderedImage().getWidth();
+    int        rasterHeight = gc.getRenderedImage().getHeight();
+    double     cellWidth    = realWidth / rasterWidth;
+    double     cellHeight   = realHeight / rasterHeight;
+
+
+    // Determine the raster cells inside the Geometry-BB
+    // -> only these are possibly intersected
+    com.vividsolutions.jts.geom.Envelope lsBB = g.getEnvelopeInternal();
+    double bbMinX = Math.max(realMinX, lsBB.getMinX());
+    double bbMinY = Math.max(realMinY, lsBB.getMinY());
+    double bbMaxX = Math.min(realMaxX, lsBB.getMaxX());
+    double bbMaxY = Math.min(realMaxY, lsBB.getMaxY());
+    int[] lsMinCell = convertRealToRaster(gc,bbMinX,bbMaxY);
+    int[] lsMaxCell = convertRealToRaster(gc,bbMaxX,bbMinY);
+
+    bbMinX = realMinX + lsMinCell[0] * cellWidth;
+    bbMaxX = realMinX + (lsMaxCell[0]+1) * cellWidth;
+    bbMinY = realMinY + (rasterHeight-(lsMaxCell[1]+1)) * cellHeight;
+    bbMaxY = realMinY + (rasterHeight-lsMinCell[1]) * cellHeight;
+
+    // Check all raster cells inside the BB of the Geometry, whether they
+    // really intersect the Geometry
+    Coordinate[]    cellBounds = new Coordinate[] { new Coordinate(), new Coordinate(), new Coordinate(), new Coordinate(), new Coordinate() };
+    GeometryFactory geomFac    = new GeometryFactory();
+    for (double y = bbMinY; y<=bbMaxY; y+=cellHeight)
+      for (double x = bbMinX; x<=bbMaxX; x+=cellWidth) {
+        cellBounds[0].x = x;
+        cellBounds[0].y = y;
+        cellBounds[1].x = x+cellWidth;
+        cellBounds[1].y = y;
+        cellBounds[2].x = x+cellWidth;
+        cellBounds[2].y = y+cellHeight;
+        cellBounds[3].x = x;
+        cellBounds[3].y = y+cellHeight;
+        cellBounds[4]   = cellBounds[0];
+        if ( g.intersects(geomFac.createLinearRing(cellBounds)) ) {
+          int[] cell = convertRealToRaster(gc, x, y);
+          switch ( sampleType ) {
+            case DataBuffer.TYPE_BYTE:
+            case DataBuffer.TYPE_SHORT:
+            case DataBuffer.TYPE_USHORT:
+            case DataBuffer.TYPE_INT:
+                        result.setSample(cell[0],cell[1],band,markValue.intValue());
+                        break;
+            case DataBuffer.TYPE_FLOAT:
+                        result.setSample(cell[0],cell[1],band,markValue.floatValue());
+                        break;
+            case DataBuffer.TYPE_DOUBLE:
+                        result.setSample(cell[0],cell[1],band,markValue.doubleValue());
+                        break;
+          }
+        }
+      }
+
+    return result;
+  }
+
+
+  /**
+   * Marks all raster cells, which are intersected by a {@link Geometry}.
+   * @param gc the raster
+   * @param g  Geometry, checked for intersection
+   * @param markValue value the intersected cells are marked with
+   * @return <b>a NEW instance of {@link GridCoverage2D}!!</b>
+   */
+  public static GridCoverage2D getOverlappingCells(GridCoverage2D gc, Geometry g, Number markValue) {
+    WritableRaster result = getOverlappingCells(gc,g,markValue,null);
+    return new GridCoverageFactory().create("",result,gc.getEnvelope());
+  }
+}

Modified: trunk/src/schmitzm/geotools/grid/GridZoneStatistic.java
===================================================================
--- trunk/src/schmitzm/geotools/grid/GridZoneStatistic.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/grid/GridZoneStatistic.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,255 +1,273 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.grid;
-
-import java.util.SortedMap;
-import java.util.SortedSet;
-import java.util.TreeMap;
-import java.util.TreeSet;
-
-/**
- * Diese Klasse stellt Informationen ueber ein Raster dar, das in Zonen
- * unterteilt ist.
- * <ul>
- *   <li>Anzahl an Zellen pro Zone</li>
- *   <li>Summe der Zellwerte pro Zone</li>
- *   <li>Durchschnitt der Zellwerte pro Zone</li>
- *   <li>Anzahl an Zellen eines bestimmten Werts pro Zone</li>
- * </ul>
- * Der Typ, durch den die Zonen identifiziert werden, wird zum Instanzieerungszeitpunkt
- * durch {@code <Z>} festgelegt.
- * @see GridUtil#determineZoneStatistic(GridCoverage2D,GridCoverage2D)}.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class GridZoneStatistic<Z> {
-  /** Speichert Nummern der Zonen. */
-  protected SortedSet<Z>  zones = null;
-  /** Speichert die Anzahl der Zellen pro Zone und Wert. */
-  protected SortedMap<Z, SortedMap<Double,Integer>> detailCellCounts = null;
-  /** Speichert die Anzahl der Zellen pro Zone. */
-  protected SortedMap<Z, Integer> totalCellCounts = null;
-  /** Speichert die Summe der Zellwerte pro Zone. */
-  protected SortedMap<Z, Double>  cellSums = null;
-  /** Speichert den Durchschnitt der Zellwerte pro Zone. */
-  protected SortedMap<Z, Double>  cellAvgs = null;
-
-  /**
-   * Erzeugt eine leere {@code GridZoneStatistic}. Die Werte der Zonen muessen
-   * mittles {@link setZoneStatistic(int,int,double} gesetzt werden.
-   */
-  public GridZoneStatistic() {
-    this( new TreeMap<Z, Integer>(),  new TreeMap<Z, SortedMap<Double,Integer>>(), new TreeMap<Z, Double>(), new TreeMap<Z, Double>());
-  }
-
-  /**
-   * Erzeugt eine {@code GridZoneStatistic}.
-   * @param cellCounts Anzahl an Zellen pro Zone
-   * @param cellSums   Summe der Zellwerte pro Zone
-   */
-  public GridZoneStatistic(SortedMap<Z, Integer> totalCellCounts, SortedMap<Z, SortedMap<Double,Integer>> detailCellCounts, SortedMap<Z, Double> cellSums) {
-    this(totalCellCounts, detailCellCounts, cellSums, new TreeMap<Z, Double>());
-    for (Z zone : getZones()) {
-      int    cellCount = getTotalCellCount(zone);
-      double cellSum   = getCellSum(zone);
-      cellAvgs.put(zone, cellCount != 0 ? cellSum / cellCount : 0);
-    }
-  }
-
-  /**
-   * Erzeugt eine {@code GridZoneStatistic}.
-   * @param cellCounts Anzahl an Zellen pro Zone
-   * @param cellSums   Summe der Zellwerte pro Zone
-   * @param cellAvgs   Durchschnittswert der Zellen pro Zone
-   */
-  public GridZoneStatistic(SortedMap<Z, Integer> totalCellCounts, SortedMap<Z, SortedMap<Double,Integer>> detailCellCounts, SortedMap<Z, Double> cellSums, SortedMap<Z, Double> cellAvgs) {
-    this.cellSums   = cellSums;
-    this.cellAvgs   = cellAvgs;
-    this.detailCellCounts = detailCellCounts;
-    this.totalCellCounts = totalCellCounts;
-    this.zones      = new TreeSet( totalCellCounts.keySet() );
-  }
-
-  /**
-   * Liefert die Anzahl an Zonen.
-   */
-  public int getZoneCount() {
-    return zones.size();
-  }
-
-  /**
-   * Liefert die Nummern der Zonen.
-   */
-  public SortedSet<Z> getZones() {
-    return zones;
-  }
-
-  /**
-   * Prueft, ob es eine bestimmte Zone gibt.
-   * @param zone Nummer der Zone
-   */
-  public boolean containsZone(Z zone) {
-    return zones.contains(zone);
-  }
-
-  /**
-   * Leert die Statistik fuer eine Zone.
-   * @param zone Nummer der Zone
-   */
-  public void clearZoneStatistic(Z zone) {
-    zones.remove(zone);
-    cellAvgs.remove(zone);
-    cellSums.remove(zone);
-    totalCellCounts.remove(zone);
-    detailCellCounts.remove(zone);
-  }
-
-  /**
-   * Leert die Statistik aller Zonen.
-   */
-  public void clearZoneStatistic() {
-    while (!zones.isEmpty())
-      clearZoneStatistic( zones.first() );
-  }
-
-  /**
-   * Fuegt der Statistik einer Zone einen Wert hinzu.
-   * @param zone Nummer der Zone
-   * @param cellValue Zell-Wert
-   */
-  public void addValueToZoneStatistic(Z zone, double cellValue)
-  {
-    // Anzahl der Zellen des bestimmten Werts in Zone erhoehen
-    if ( !detailCellCounts.containsKey(zone) )
-      detailCellCounts.put(zone, new TreeMap<Double,Integer>());
-    SortedMap<Double,Integer> detailCellCount = this.detailCellCounts.get(zone);
-    detailCellCount.put(cellValue, getDetailCellCount(zone,cellValue)+1);
-    // Gesamtanzahl der Zonenwerte erhoehen
-    int cellCount = getTotalCellCount(zone)+1;
-    this.totalCellCounts.put(zone, cellCount);
-    // Gesamtsumme der Zonenwerte erhoehen
-    double cellSum = getCellSum(zone)+cellValue;
-    this.cellSums.put(zone, cellSum);
-    // Durchschnittswert der Zone erneuern
-    this.cellAvgs.put(zone, cellCount != 0 ? cellSum/cellCount : 0 );
-    // ggf. neue Zone in Zonen-Liste aufnehmen
-    this.zones.add(zone);
-  }
-
-  /**
-   * Liefert die Anzahl an Zellen in einer Zone
-   * @param zone Nummer der Zone
-   * @return 0 falls es die Zone nicht gibt
-   */
-  public int getTotalCellCount(Z zone) {
-    return (int)getValueFromZoneMap(zone, totalCellCounts);
-  }
-
-  /**
-   * Liefert die Anzahl an Zellen eines bestimmten Werts in einer Zone.
-   * @param zone Nummer der Zone
-   * @param cellValue Zell-Wert
-   * @return 0 falls es die Zone nicht gibt
-   */
-  public int getDetailCellCount(Z zone, double cellValue) {
-    SortedMap<Double,Integer> cellCounts = detailCellCounts.get(zone);
-    if ( cellCounts == null )
-      return 0;
-    Integer count = cellCounts.get(cellValue);
-    return count == null ? 0 : count.intValue();
-  }
-
-  /**
-   * Liefert die Zellenanzahl differenziert nach Zellwert fuer alle Zonen.
-   */
-  public SortedMap<Z, SortedMap<Double,Integer>> getDetailCellCountMap() {
-    return this.detailCellCounts;
-  }
-
-  /**
-   * Liefert die Zellenanzahl differenziert nach Zellwert fuer eine Zone.
-   * @param zone Nummer der Zone
-   */
-  public SortedMap<Double,Integer> getDetailCellCountMap(Z zone) {
-    return this.detailCellCounts.get(zone);
-  }
-
-  /**
-   * Liefert Anzahl an verschiedenen Zellen fuer eine Zone.
-   * @param zone Nummer der Zone
-   */
-  public int getValueCount(Z zone) {
-    if ( !containsZone(zone) )
-      return 0;
-    return this.detailCellCounts.get(zone).size();
-  }
-
-  /**
-   * Liefert die verschiedenen Werte, die in einer Zone vorkommen.
-   * @param zone Nummer der Zone
-   */
-  public SortedSet<Double> getValues(Z zone) {
-    if ( !containsZone(zone) )
-      return new TreeSet<Double>();
-    return new TreeSet<Double>( this.detailCellCounts.get(zone).keySet() );
-  }
-
-  /**
-   * Liefert die Gesamt-Zellenanzahl pro Zone als Map.
-   */
-  public SortedMap<Z, Integer> getTotalCellCountMap() {
-    return this.totalCellCounts;
-  }
-
-  /**
-   * Liefert die Summe der Zell-Werte in einer Zone
-   * @param zone Nummer der Zone
-   * @return 0 falls es die Zone nicht gibt
-   */
-  public double getCellSum(Z zone) {
-    return getValueFromZoneMap(zone, cellSums);
-  }
-
-  /**
-   * Liefert die Summen der Zellwerte pro Zone als Map.
-   */
-  public SortedMap<Z, Double> getCellSumMap() {
-    return this.cellSums;
-  }
-
-  /**
-   * Liefert den Durchschnitt der Zell-Werte in einer Zone
-   * @param zone Nummer der Zone
-   * @return 0 falls es die Zone nicht gibt
-   */
-  public double getCellAvg(Z zone) {
-    return getValueFromZoneMap(zone, cellAvgs);
-  }
-
-  /**
-   * Liefert die Durchschnittswerte der Zellen pro Zone als Map.
-   */
-  public SortedMap<Z, Double> getCellAvgMap() {
-    return this.cellAvgs;
-  }
-
-  /**
-   * Liefert einen Wert aus einer Zonen-Map.
-   * @param zone Nummer der Zone
-   * @param map eine Map
-   * @return 0, falls es in der Map keinen Eintrag fuer die Zone gibt
-   */
-  private <T extends Number> double getValueFromZoneMap(Z zone, SortedMap<Z, T> map) {
-    Number value = map.get(zone);
-    return value != null ? value.doubleValue() : 0;
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.grid;
+
+import java.util.SortedMap;
+import java.util.SortedSet;
+import java.util.TreeMap;
+import java.util.TreeSet;
+
+/**
+ * Diese Klasse stellt Informationen ueber ein Raster dar, das in Zonen
+ * unterteilt ist.
+ * <ul>
+ *   <li>Anzahl an Zellen pro Zone</li>
+ *   <li>Summe der Zellwerte pro Zone</li>
+ *   <li>Durchschnitt der Zellwerte pro Zone</li>
+ *   <li>Anzahl an Zellen eines bestimmten Werts pro Zone</li>
+ * </ul>
+ * Der Typ, durch den die Zonen identifiziert werden, wird zum Instanzieerungszeitpunkt
+ * durch {@code <Z>} festgelegt.
+ * @see GridUtil#determineZoneStatistic(GridCoverage2D,GridCoverage2D)}.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class GridZoneStatistic<Z> {
+  /** Speichert Nummern der Zonen. */
+  protected SortedSet<Z>  zones = null;
+  /** Speichert die Anzahl der Zellen pro Zone und Wert. */
+  protected SortedMap<Z, SortedMap<Double,Integer>> detailCellCounts = null;
+  /** Speichert die Anzahl der Zellen pro Zone. */
+  protected SortedMap<Z, Integer> totalCellCounts = null;
+  /** Speichert die Summe der Zellwerte pro Zone. */
+  protected SortedMap<Z, Double>  cellSums = null;
+  /** Speichert den Durchschnitt der Zellwerte pro Zone. */
+  protected SortedMap<Z, Double>  cellAvgs = null;
+
+  /**
+   * Erzeugt eine leere {@code GridZoneStatistic}. Die Werte der Zonen muessen
+   * mittles {@link setZoneStatistic(int,int,double} gesetzt werden.
+   */
+  public GridZoneStatistic() {
+    this( new TreeMap<Z, Integer>(),  new TreeMap<Z, SortedMap<Double,Integer>>(), new TreeMap<Z, Double>(), new TreeMap<Z, Double>());
+  }
+
+  /**
+   * Erzeugt eine {@code GridZoneStatistic}.
+   * @param cellCounts Anzahl an Zellen pro Zone
+   * @param cellSums   Summe der Zellwerte pro Zone
+   */
+  public GridZoneStatistic(SortedMap<Z, Integer> totalCellCounts, SortedMap<Z, SortedMap<Double,Integer>> detailCellCounts, SortedMap<Z, Double> cellSums) {
+    this(totalCellCounts, detailCellCounts, cellSums, new TreeMap<Z, Double>());
+    for (Z zone : getZones()) {
+      int    cellCount = getTotalCellCount(zone);
+      double cellSum   = getCellSum(zone);
+      cellAvgs.put(zone, cellCount != 0 ? cellSum / cellCount : 0);
+    }
+  }
+
+  /**
+   * Erzeugt eine {@code GridZoneStatistic}.
+   * @param cellCounts Anzahl an Zellen pro Zone
+   * @param cellSums   Summe der Zellwerte pro Zone
+   * @param cellAvgs   Durchschnittswert der Zellen pro Zone
+   */
+  public GridZoneStatistic(SortedMap<Z, Integer> totalCellCounts, SortedMap<Z, SortedMap<Double,Integer>> detailCellCounts, SortedMap<Z, Double> cellSums, SortedMap<Z, Double> cellAvgs) {
+    this.cellSums   = cellSums;
+    this.cellAvgs   = cellAvgs;
+    this.detailCellCounts = detailCellCounts;
+    this.totalCellCounts = totalCellCounts;
+    this.zones      = new TreeSet( totalCellCounts.keySet() );
+  }
+
+  /**
+   * Liefert die Anzahl an Zonen.
+   */
+  public int getZoneCount() {
+    return zones.size();
+  }
+
+  /**
+   * Liefert die Nummern der Zonen.
+   */
+  public SortedSet<Z> getZones() {
+    return zones;
+  }
+
+  /**
+   * Prueft, ob es eine bestimmte Zone gibt.
+   * @param zone Nummer der Zone
+   */
+  public boolean containsZone(Z zone) {
+    return zones.contains(zone);
+  }
+
+  /**
+   * Leert die Statistik fuer eine Zone.
+   * @param zone Nummer der Zone
+   */
+  public void clearZoneStatistic(Z zone) {
+    zones.remove(zone);
+    cellAvgs.remove(zone);
+    cellSums.remove(zone);
+    totalCellCounts.remove(zone);
+    detailCellCounts.remove(zone);
+  }
+
+  /**
+   * Leert die Statistik aller Zonen.
+   */
+  public void clearZoneStatistic() {
+    while (!zones.isEmpty())
+      clearZoneStatistic( zones.first() );
+  }
+
+  /**
+   * Fuegt der Statistik einer Zone einen Wert hinzu.
+   * @param zone Nummer der Zone
+   * @param cellValue Zell-Wert
+   */
+  public void addValueToZoneStatistic(Z zone, double cellValue)
+  {
+    // Anzahl der Zellen des bestimmten Werts in Zone erhoehen
+    if ( !detailCellCounts.containsKey(zone) )
+      detailCellCounts.put(zone, new TreeMap<Double,Integer>());
+    SortedMap<Double,Integer> detailCellCount = this.detailCellCounts.get(zone);
+    detailCellCount.put(cellValue, getDetailCellCount(zone,cellValue)+1);
+    // Gesamtanzahl der Zonenwerte erhoehen
+    int cellCount = getTotalCellCount(zone)+1;
+    this.totalCellCounts.put(zone, cellCount);
+    // Gesamtsumme der Zonenwerte erhoehen
+    double cellSum = getCellSum(zone)+cellValue;
+    this.cellSums.put(zone, cellSum);
+    // Durchschnittswert der Zone erneuern
+    this.cellAvgs.put(zone, cellCount != 0 ? cellSum/cellCount : 0 );
+    // ggf. neue Zone in Zonen-Liste aufnehmen
+    this.zones.add(zone);
+  }
+
+  /**
+   * Liefert die Anzahl an Zellen in einer Zone
+   * @param zone Nummer der Zone
+   * @return 0 falls es die Zone nicht gibt
+   */
+  public int getTotalCellCount(Z zone) {
+    return (int)getValueFromZoneMap(zone, totalCellCounts);
+  }
+
+  /**
+   * Liefert die Anzahl an Zellen eines bestimmten Werts in einer Zone.
+   * @param zone Nummer der Zone
+   * @param cellValue Zell-Wert
+   * @return 0 falls es die Zone nicht gibt
+   */
+  public int getDetailCellCount(Z zone, double cellValue) {
+    SortedMap<Double,Integer> cellCounts = detailCellCounts.get(zone);
+    if ( cellCounts == null )
+      return 0;
+    Integer count = cellCounts.get(cellValue);
+    return count == null ? 0 : count.intValue();
+  }
+
+  /**
+   * Liefert die Zellenanzahl differenziert nach Zellwert fuer alle Zonen.
+   */
+  public SortedMap<Z, SortedMap<Double,Integer>> getDetailCellCountMap() {
+    return this.detailCellCounts;
+  }
+
+  /**
+   * Liefert die Zellenanzahl differenziert nach Zellwert fuer eine Zone.
+   * @param zone Nummer der Zone
+   */
+  public SortedMap<Double,Integer> getDetailCellCountMap(Z zone) {
+    return this.detailCellCounts.get(zone);
+  }
+
+  /**
+   * Liefert Anzahl an verschiedenen Zellen fuer eine Zone.
+   * @param zone Nummer der Zone
+   */
+  public int getValueCount(Z zone) {
+    if ( !containsZone(zone) )
+      return 0;
+    return this.detailCellCounts.get(zone).size();
+  }
+
+  /**
+   * Liefert die verschiedenen Werte, die in einer Zone vorkommen.
+   * @param zone Nummer der Zone
+   */
+  public SortedSet<Double> getValues(Z zone) {
+    if ( !containsZone(zone) )
+      return new TreeSet<Double>();
+    return new TreeSet<Double>( this.detailCellCounts.get(zone).keySet() );
+  }
+
+  /**
+   * Liefert die Gesamt-Zellenanzahl pro Zone als Map.
+   */
+  public SortedMap<Z, Integer> getTotalCellCountMap() {
+    return this.totalCellCounts;
+  }
+
+  /**
+   * Liefert die Summe der Zell-Werte in einer Zone
+   * @param zone Nummer der Zone
+   * @return 0 falls es die Zone nicht gibt
+   */
+  public double getCellSum(Z zone) {
+    return getValueFromZoneMap(zone, cellSums);
+  }
+
+  /**
+   * Liefert die Summen der Zellwerte pro Zone als Map.
+   */
+  public SortedMap<Z, Double> getCellSumMap() {
+    return this.cellSums;
+  }
+
+  /**
+   * Liefert den Durchschnitt der Zell-Werte in einer Zone
+   * @param zone Nummer der Zone
+   * @return 0 falls es die Zone nicht gibt
+   */
+  public double getCellAvg(Z zone) {
+    return getValueFromZoneMap(zone, cellAvgs);
+  }
+
+  /**
+   * Liefert die Durchschnittswerte der Zellen pro Zone als Map.
+   */
+  public SortedMap<Z, Double> getCellAvgMap() {
+    return this.cellAvgs;
+  }
+
+  /**
+   * Liefert einen Wert aus einer Zonen-Map.
+   * @param zone Nummer der Zone
+   * @param map eine Map
+   * @return 0, falls es in der Map keinen Eintrag fuer die Zone gibt
+   */
+  private <T extends Number> double getValueFromZoneMap(Z zone, SortedMap<Z, T> map) {
+    Number value = map.get(zone);
+    return value != null ? value.doubleValue() : 0;
+  }
+}

Modified: trunk/src/schmitzm/geotools/grid/ReadableGridCoverage.java
===================================================================
--- trunk/src/schmitzm/geotools/grid/ReadableGridCoverage.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/grid/ReadableGridCoverage.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,395 +1,413 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.grid;
-
-import java.awt.image.DataBuffer;
-import java.awt.image.Raster;
-import java.util.Map;
-
-import javax.media.jai.PlanarImage;
-
-import org.geotools.coverage.GridSampleDimension;
-import org.geotools.coverage.grid.GridCoverage2D;
-import org.geotools.coverage.grid.GridGeometry2D;
-import org.geotools.geometry.Envelope2D;
-import org.opengis.coverage.grid.GridCoverage;
-
-import schmitzm.data.AbstractReadableGrid;
-import schmitzm.data.ReadableGrid;
-import appl.data.LoadingException;
-
-/**
- * Diese Klasse stellt ein {@linkplain GridCoverage2D GeoTools-GridCoverage} (2D) dar,
- * welches auf einem {@link Raster} basiert und darauf direkten
- * Lese- und Schreibzugriff liefert.<br>
- * Auch wenn {@link Raster} prinzipell mehrere Dimensionen (Baender)
- * zulaesst, sind die Zugriffsmethoden dieser Klasse auf ein Band beschraenkt.<br>
- * <br>
- * <br>Um Instanzen dieser Klasse zu erzeugen, sollten die Factory-Methoden
- * {@code create(.)} verwendet werden!</b>
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class ReadableGridCoverage extends GridCoverage2D implements ReadableGrid {
-  /**
-   * Speichert die Datenbasis des Grids.
-   */
-  protected Raster raster = null;
-
-  /**
-   * Speichert das Band des {@link #raster WritableRasters}, welches durch dieses
-   * Grid angesprochen wird.
-   */
-  protected int band   = 0;
-
-  /**
-   * Speichert die Informationen ueber die GeoReferenz des Rasters.
-   */
-  protected Envelope2D envelope = null;
-
-  /**
-   * Ruft den Standard-Konstruktor der von {@link GridCoverage2D} auf.
-   * @param name          Name des Grids
-   * @param image         Image-Daten
-   * @param gridGeometry  Georeferenz und CRS
-   * @param bands         Sample-Dimensions fuer jedes Band (kann {@code null} sein)
-   * @param sources       Quell-Grids (kann {@code null} sein
-   * @param properties    Properties fuer das Grid (kann {@code null} sein)
-   * @param band          Band der Datenbasis, auf das die getter/setter referenziert sind
-   */
-  protected ReadableGridCoverage(CharSequence name, PlanarImage image, GridGeometry2D gridGeometry, GridSampleDimension[] bands, GridCoverage[] sources, Map properties, int band) {
-    super( name, image, gridGeometry, bands, sources, properties );
-    this.raster   = getRenderedImage().getData();
-    this.band     = band;
-    this.envelope = getEnvelope2D();
-  }
-
-  /**
-   * Erzeugt ein neues Grid.
-   * @param gc   Datenbasis fuer das Grid
-   * @param band Band der Datenbasis, auf das die getter/setter referenziert sind
-   */
-  public static ReadableGridCoverage create(GridCoverage2D gc, int band) {
-    return new ReadableGridCoverage(
-      gc.getName().toString(),
-      PlanarImage.wrapRenderedImage(gc.getRenderedImage()),
-      (GridGeometry2D)gc.getGridGeometry(),
-      gc.getSampleDimensions(),
-      null,
-      null,
-      band
-    );
-  }
-
-  /**
-   * Liefert eine direkte Referenz auf die Datenbasis.
-   */
-  public Raster getRaster() {
-    return raster;
-  }
-
-  /**
-   * Liefert die Breite des Rasters (in Zellen).
-   */
-  public int getWidth() {
-    return raster.getWidth();
-  }
-
-  /**
-   * Liefert die Hoehe des Rasters (in Zellen).
-   */
-  public int getHeight() {
-    return raster.getHeight();
-  }
-
-  /**
-   * Liefert den Index der ersten Zelle (Südwest) in X-Richtung.
-   */
-  public int getMinX() {
-    return raster.getMinX();
-  }
-
-  /**
-   * Liefert den Index der ersten Zelle (Südwest) in Y-Richtung.
-   */
-  public int getMinY() {
-    return raster.getMinY();
-  }
-
-  /**
-   * Liefert die reale Breite des Rasters.
-   */
-  public double getRealWidth() {
-    return envelope.getLength(0);
-  }
-
-  /**
-   * Liefert die reale Breite des Rasters.
-   */
-  public double getRealHeight() {
-    return envelope.getLength(1);
-  }
-
-  /**
-   * Liefert die reale Breite einer Rasterzelle.
-   * @return <code>getRealWidth() / getWidth()</code>
-   */
-  public double getCellWidth() {
-    return getRealWidth() / getWidth();
-  }
-
-  /**
-   * Liefert die reale Breite einer Rasterzelle.
-   * @return <code>getRealHeight() / getHeight()</code>
-   */
-  public double getCellHeight() {
-    return getRealHeight() / getHeight();
-  }
-
-  /**
-   * Liefert die X-Koordinate der Georeferenz (Longitude) der linken unteren
-   * Ecke des Rasters (Südwest).
-   */
-  public double getX() {
-    return envelope.getX();
-  }
-
-  /**
-   * Liefert die Y-Koordinate der Georeferenz (Latitude) der linken unteren
-   * Ecke des Rasters (Südwest).
-   */
-  public double getY() {
-    return envelope.getY();
-  }
-
-  /**
-   * Liefert die Art der Daten, die im Raster gespeichert werden koennen. Diese
-   * wird durch eine der TYPE-Konstanten in {@link DataBuffer}
-   * repraesentiert.
-   */
-  public int getSampleType() {
-    return raster.getDataBuffer().getDataType();
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
-   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-   *             {@link #getMinX()} und {@link #getMinY()})
-   * @return je nach {@linkplain #getSampleType() Art} des Rasters einen
-   *         <code>int</code>, <code>float</code> oder <code>double</code>
-   * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
-   *            Koordinaten angegeben werden
-   */
-  public Object getRasterSample(int... cell) {
-    if ( cell.length < RASTER_DIM )
-      throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
-//    // Bei 'raster' (WritableRaster) beginnen die Raster-Koordinaten in der
-//    // linken oberen Ecke. Im Grid soll die Zaehlung jedoch in der linken unteren
-//    // Ecke beginnen -> Y-Koordinate umrechnen
-//    int x = cell[0];
-//    int y = getMinY() + getHeight()-1 - cell[1];
-    // Bei 'raster' (WritableRaster) beginnen die Raster-Koordinaten in der
-    // linken oberen Ecke. Im Grid soll es genauso sein!
-    int x = cell[0];
-    int y = cell[1];
-    Object value = null;
-    switch ( getSampleType() ) {
-      case DataBuffer.TYPE_BYTE:
-      case DataBuffer.TYPE_SHORT:
-      case DataBuffer.TYPE_USHORT:
-      case DataBuffer.TYPE_INT:    value = raster.getSample(x,y,band); break;
-      case DataBuffer.TYPE_FLOAT:  value = raster.getSampleFloat(x,y,band); break;
-      case DataBuffer.TYPE_DOUBLE: value = raster.getSampleDouble(x,y,band); break;
-      default:                     value = raster.getSample(x,y,band); break;
-    }
-    return value;
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
-   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-   *             {@link #getMinX()} und {@link #getMinY()})
-   */
-  public short getRasterSampleAsShort(int... cell) {
-    return ((Number)getRasterSample(cell)).shortValue();
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
-   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-   *             {@link #getMinX()} und {@link #getMinY()})
-   */
-  public byte getRasterSampleAsByte(int... cell) {
-    return ((Number)getRasterSample(cell)).byteValue();
-  }
-
-
-  /**
-   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
-   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-   *             {@link #getMinX()} und {@link #getMinY()})
-   */
-  public int getRasterSampleAsInt(int... cell) {
-    return ((Number)getRasterSample(cell)).intValue();
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
-   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-   *             {@link #getMinX()} und {@link #getMinY()})
-   */
-  public long getRasterSampleAsLong(int... cell) {
-    return ((Number)getRasterSample(cell)).longValue();
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
-   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-   *             {@link #getMinX()} und {@link #getMinY()})
-   */
-  public float getRasterSampleAsFloat(int... cell) {
-    return ((Number)getRasterSample(cell)).floatValue();
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
-   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
-   *             {@link #getMinX()} und {@link #getMinY()})
-   */
-  public double getRasterSampleAsDouble(int... cell) {
-    return ((Number)getRasterSample(cell)).doubleValue();
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
-   * Liegt der Koordinatenwert genau auf der Grenze zwischen zwei Rasterzellen,
-   * wird die naechst groessere Zelle gewaehlt (ausser die Grenze entspricht
-   * dem Raster-Rand!).
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
-   *            Koordinaten angegeben werden
-   */
-  public Object getGridSample(double... coord) {
-    if ( coord.length < RASTER_DIM )
-      throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
-    // Koordinaten umrechnen in Zellen-Index
-    int cellX = convertRealToRaster(coord[0],0);
-    int cellY = convertRealToRaster(coord[1],1);
-    return getRasterSample(cellX,cellY);
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   */
-  public short getGridSampleAsShort(double... coord) {
-    return ((Number)getGridSample(coord)).shortValue();
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   */
-  public byte getGridSampleAsByte(double... coord){
-    return ((Number)getGridSample(coord)).byteValue();
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   */
-  public int getGridSampleAsInt(double... coord){
-    return ((Number)getGridSample(coord)).intValue();
-  }
-
-
-  /**
-   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   */
-  public long getGridSampleAsLong(double... coord){
-    return ((Number)getGridSample(coord)).longValue();
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   */
-  public float getGridSampleAsFloat(double... coord){
-    return ((Number)getGridSample(coord)).floatValue();
-  }
-
-
-  /**
-   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   */
-  public double getGridSampleAsDouble(double... coord){
-    return ((Number)getGridSample(coord)).doubleValue();
-  }
-
-  /**
-   * Konvertiert eine reale Koordinate in eine Zellennummer. Liegt der
-   * Koordinatenwert genau auf der Grenze zwischen zwei Rasterzellen, wird
-   * die naechst "groessere" Zellegewaehlt.
-   * Ausnahme bildet der Rand des Rasters. Hier wird die kleinere Zelle
-   * (also die letzte) herangezogen
-   * @param coord Georeferenz-Koordinate
-   * @param dim   Dimension, in der die Umrechnung erfolgen soll
-   * @exception UnsupportedOperationException falls eine ungueltige Dimension
-   *            angegeben wird (nur Werte 0 <= coord < {@link #RASTER_DIM} sind
-   *            zulaessig
-   */
-  public int convertRealToRaster(double coord, int dim) {
-    return AbstractReadableGrid.convertRealToRaster(this,coord,dim);
-  }
-
-  /**
-   * Konvertiert eine Zellennummer in reale Koordinate. Dabei wird die
-   * Koordinate der Zellenmitte zurueckgegeben.
-   * @param cell  Rasterzellen-Koordinate
-   * @param dim   Dimension, in der die Umrechnung erfolgen soll
-   * @exception UnsupportedOperationException falls eine ungueltige Dimension
-   *            angegeben wird (nur Werte 0 <= coord < {@link #RASTER_DIM} sind
-   *            zulaessig
-   */
-  public double convertRasterToReal(int cell, int dim) {
-    return AbstractReadableGrid.convertRasterToReal(this,cell,dim);
-  }
-
-  /**
-   * This class does not support late loading!
-   * @see appl.data.LateLoadable#unloadData()
-   * @return false;
-   * @see appl.data.LateLoadable#isLateLoadable()
-   */
-  public boolean isLateLoadable() {
-    return false;
-  }
-
-  /**
-   * Does nothing!
-   * This class does not support late loading!
-   * @see appl.data.LateLoadable#unloadData()
-   * @see appl.data.LateLoadable#loadData()
-   */
-  public void loadData() throws LoadingException {
-  }
-
-  /**
-   * Does nothing!
-   * This class does not support late loading!
-   * @see appl.data.LateLoadable#unloadData()
-   */
-  public void unloadData() {
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.grid;
+
+import java.awt.image.DataBuffer;
+import java.awt.image.Raster;
+import java.util.Map;
+
+import javax.media.jai.PlanarImage;
+
+import org.geotools.coverage.GridSampleDimension;
+import org.geotools.coverage.grid.GridCoverage2D;
+import org.geotools.coverage.grid.GridGeometry2D;
+import org.geotools.geometry.Envelope2D;
+import org.opengis.coverage.grid.GridCoverage;
+
+import schmitzm.data.AbstractReadableGrid;
+import schmitzm.data.ReadableGrid;
+import appl.data.LoadingException;
+
+/**
+ * Diese Klasse stellt ein {@linkplain GridCoverage2D GeoTools-GridCoverage} (2D) dar,
+ * welches auf einem {@link Raster} basiert und darauf direkten
+ * Lese- und Schreibzugriff liefert.<br>
+ * Auch wenn {@link Raster} prinzipell mehrere Dimensionen (Baender)
+ * zulaesst, sind die Zugriffsmethoden dieser Klasse auf ein Band beschraenkt.<br>
+ * <br>
+ * <br>Um Instanzen dieser Klasse zu erzeugen, sollten die Factory-Methoden
+ * {@code create(.)} verwendet werden!</b>
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class ReadableGridCoverage extends GridCoverage2D implements ReadableGrid {
+  /**
+   * Speichert die Datenbasis des Grids.
+   */
+  protected Raster raster = null;
+
+  /**
+   * Speichert das Band des {@link #raster WritableRasters}, welches durch dieses
+   * Grid angesprochen wird.
+   */
+  protected int band   = 0;
+
+  /**
+   * Speichert die Informationen ueber die GeoReferenz des Rasters.
+   */
+  protected Envelope2D envelope = null;
+
+  /**
+   * Ruft den Standard-Konstruktor der von {@link GridCoverage2D} auf.
+   * @param name          Name des Grids
+   * @param image         Image-Daten
+   * @param gridGeometry  Georeferenz und CRS
+   * @param bands         Sample-Dimensions fuer jedes Band (kann {@code null} sein)
+   * @param sources       Quell-Grids (kann {@code null} sein
+   * @param properties    Properties fuer das Grid (kann {@code null} sein)
+   * @param band          Band der Datenbasis, auf das die getter/setter referenziert sind
+   */
+  protected ReadableGridCoverage(CharSequence name, PlanarImage image, GridGeometry2D gridGeometry, GridSampleDimension[] bands, GridCoverage[] sources, Map properties, int band) {
+    super( name, image, gridGeometry, bands, sources, properties );
+    this.raster   = getRenderedImage().getData();
+    this.band     = band;
+    this.envelope = getEnvelope2D();
+  }
+
+  /**
+   * Erzeugt ein neues Grid.
+   * @param gc   Datenbasis fuer das Grid
+   * @param band Band der Datenbasis, auf das die getter/setter referenziert sind
+   */
+  public static ReadableGridCoverage create(GridCoverage2D gc, int band) {
+    return new ReadableGridCoverage(
+      gc.getName().toString(),
+      PlanarImage.wrapRenderedImage(gc.getRenderedImage()),
+      (GridGeometry2D)gc.getGridGeometry(),
+      gc.getSampleDimensions(),
+      null,
+      null,
+      band
+    );
+  }
+
+  /**
+   * Liefert eine direkte Referenz auf die Datenbasis.
+   */
+  public Raster getRaster() {
+    return raster;
+  }
+
+  /**
+   * Liefert die Breite des Rasters (in Zellen).
+   */
+  public int getWidth() {
+    return raster.getWidth();
+  }
+
+  /**
+   * Liefert die Hoehe des Rasters (in Zellen).
+   */
+  public int getHeight() {
+    return raster.getHeight();
+  }
+
+  /**
+   * Liefert den Index der ersten Zelle (Südwest) in X-Richtung.
+   */
+  public int getMinX() {
+    return raster.getMinX();
+  }
+
+  /**
+   * Liefert den Index der ersten Zelle (Südwest) in Y-Richtung.
+   */
+  public int getMinY() {
+    return raster.getMinY();
+  }
+
+  /**
+   * Liefert die reale Breite des Rasters.
+   */
+  public double getRealWidth() {
+    return envelope.getLength(0);
+  }
+
+  /**
+   * Liefert die reale Breite des Rasters.
+   */
+  public double getRealHeight() {
+    return envelope.getLength(1);
+  }
+
+  /**
+   * Liefert die reale Breite einer Rasterzelle.
+   * @return <code>getRealWidth() / getWidth()</code>
+   */
+  public double getCellWidth() {
+    return getRealWidth() / getWidth();
+  }
+
+  /**
+   * Liefert die reale Breite einer Rasterzelle.
+   * @return <code>getRealHeight() / getHeight()</code>
+   */
+  public double getCellHeight() {
+    return getRealHeight() / getHeight();
+  }
+
+  /**
+   * Liefert die X-Koordinate der Georeferenz (Longitude) der linken unteren
+   * Ecke des Rasters (Südwest).
+   */
+  public double getX() {
+    return envelope.getX();
+  }
+
+  /**
+   * Liefert die Y-Koordinate der Georeferenz (Latitude) der linken unteren
+   * Ecke des Rasters (Südwest).
+   */
+  public double getY() {
+    return envelope.getY();
+  }
+
+  /**
+   * Liefert die Art der Daten, die im Raster gespeichert werden koennen. Diese
+   * wird durch eine der TYPE-Konstanten in {@link DataBuffer}
+   * repraesentiert.
+   */
+  public int getSampleType() {
+    return raster.getDataBuffer().getDataType();
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
+   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+   *             {@link #getMinX()} und {@link #getMinY()})
+   * @return je nach {@linkplain #getSampleType() Art} des Rasters einen
+   *         <code>int</code>, <code>float</code> oder <code>double</code>
+   * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
+   *            Koordinaten angegeben werden
+   */
+  public Object getRasterSample(int... cell) {
+    if ( cell.length < RASTER_DIM )
+      throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
+//    // Bei 'raster' (WritableRaster) beginnen die Raster-Koordinaten in der
+//    // linken oberen Ecke. Im Grid soll die Zaehlung jedoch in der linken unteren
+//    // Ecke beginnen -> Y-Koordinate umrechnen
+//    int x = cell[0];
+//    int y = getMinY() + getHeight()-1 - cell[1];
+    // Bei 'raster' (WritableRaster) beginnen die Raster-Koordinaten in der
+    // linken oberen Ecke. Im Grid soll es genauso sein!
+    int x = cell[0];
+    int y = cell[1];
+    Object value = null;
+    switch ( getSampleType() ) {
+      case DataBuffer.TYPE_BYTE:
+      case DataBuffer.TYPE_SHORT:
+      case DataBuffer.TYPE_USHORT:
+      case DataBuffer.TYPE_INT:    value = raster.getSample(x,y,band); break;
+      case DataBuffer.TYPE_FLOAT:  value = raster.getSampleFloat(x,y,band); break;
+      case DataBuffer.TYPE_DOUBLE: value = raster.getSampleDouble(x,y,band); break;
+      default:                     value = raster.getSample(x,y,band); break;
+    }
+    return value;
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
+   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+   *             {@link #getMinX()} und {@link #getMinY()})
+   */
+  public short getRasterSampleAsShort(int... cell) {
+    return ((Number)getRasterSample(cell)).shortValue();
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
+   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+   *             {@link #getMinX()} und {@link #getMinY()})
+   */
+  public byte getRasterSampleAsByte(int... cell) {
+    return ((Number)getRasterSample(cell)).byteValue();
+  }
+
+
+  /**
+   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
+   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+   *             {@link #getMinX()} und {@link #getMinY()})
+   */
+  public int getRasterSampleAsInt(int... cell) {
+    return ((Number)getRasterSample(cell)).intValue();
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
+   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+   *             {@link #getMinX()} und {@link #getMinY()})
+   */
+  public long getRasterSampleAsLong(int... cell) {
+    return ((Number)getRasterSample(cell)).longValue();
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
+   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+   *             {@link #getMinX()} und {@link #getMinY()})
+   */
+  public float getRasterSampleAsFloat(int... cell) {
+    return ((Number)getRasterSample(cell)).floatValue();
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Raster-Koordinaten.
+   * @param cell 2D-Raster-Koordinate (Zellenindizes, beginnend bei
+   *             {@link #getMinX()} und {@link #getMinY()})
+   */
+  public double getRasterSampleAsDouble(int... cell) {
+    return ((Number)getRasterSample(cell)).doubleValue();
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
+   * Liegt der Koordinatenwert genau auf der Grenze zwischen zwei Rasterzellen,
+   * wird die naechst groessere Zelle gewaehlt (ausser die Grenze entspricht
+   * dem Raster-Rand!).
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
+   *            Koordinaten angegeben werden
+   */
+  public Object getGridSample(double... coord) {
+    if ( coord.length < RASTER_DIM )
+      throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
+    // Koordinaten umrechnen in Zellen-Index
+    int cellX = convertRealToRaster(coord[0],0);
+    int cellY = convertRealToRaster(coord[1],1);
+    return getRasterSample(cellX,cellY);
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   */
+  public short getGridSampleAsShort(double... coord) {
+    return ((Number)getGridSample(coord)).shortValue();
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   */
+  public byte getGridSampleAsByte(double... coord){
+    return ((Number)getGridSample(coord)).byteValue();
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   */
+  public int getGridSampleAsInt(double... coord){
+    return ((Number)getGridSample(coord)).intValue();
+  }
+
+
+  /**
+   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   */
+  public long getGridSampleAsLong(double... coord){
+    return ((Number)getGridSample(coord)).longValue();
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   */
+  public float getGridSampleAsFloat(double... coord){
+    return ((Number)getGridSample(coord)).floatValue();
+  }
+
+
+  /**
+   * Liefert einen Wert des Rasters ueber Geo-Koordinaten.
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   */
+  public double getGridSampleAsDouble(double... coord){
+    return ((Number)getGridSample(coord)).doubleValue();
+  }
+
+  /**
+   * Konvertiert eine reale Koordinate in eine Zellennummer. Liegt der
+   * Koordinatenwert genau auf der Grenze zwischen zwei Rasterzellen, wird
+   * die naechst "groessere" Zellegewaehlt.
+   * Ausnahme bildet der Rand des Rasters. Hier wird die kleinere Zelle
+   * (also die letzte) herangezogen
+   * @param coord Georeferenz-Koordinate
+   * @param dim   Dimension, in der die Umrechnung erfolgen soll
+   * @exception UnsupportedOperationException falls eine ungueltige Dimension
+   *            angegeben wird (nur Werte 0 <= coord < {@link #RASTER_DIM} sind
+   *            zulaessig
+   */
+  public int convertRealToRaster(double coord, int dim) {
+    return AbstractReadableGrid.convertRealToRaster(this,coord,dim);
+  }
+
+  /**
+   * Konvertiert eine Zellennummer in reale Koordinate. Dabei wird die
+   * Koordinate der Zellenmitte zurueckgegeben.
+   * @param cell  Rasterzellen-Koordinate
+   * @param dim   Dimension, in der die Umrechnung erfolgen soll
+   * @exception UnsupportedOperationException falls eine ungueltige Dimension
+   *            angegeben wird (nur Werte 0 <= coord < {@link #RASTER_DIM} sind
+   *            zulaessig
+   */
+  public double convertRasterToReal(int cell, int dim) {
+    return AbstractReadableGrid.convertRasterToReal(this,cell,dim);
+  }
+
+  /**
+   * This class does not support late loading!
+   * @see appl.data.LateLoadable#unloadData()
+   * @return false;
+   * @see appl.data.LateLoadable#isLateLoadable()
+   */
+  public boolean isLateLoadable() {
+    return false;
+  }
+
+  /**
+   * Does nothing!
+   * This class does not support late loading!
+   * @see appl.data.LateLoadable#unloadData()
+   * @see appl.data.LateLoadable#loadData()
+   */
+  public void loadData() throws LoadingException {
+  }
+
+  /**
+   * Does nothing!
+   * This class does not support late loading!
+   * @see appl.data.LateLoadable#unloadData()
+   */
+  public void unloadData() {
+  }
+}

Modified: trunk/src/schmitzm/geotools/grid/WritableGridCoverage.java
===================================================================
--- trunk/src/schmitzm/geotools/grid/WritableGridCoverage.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/grid/WritableGridCoverage.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,200 +1,218 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.grid;
-
-import java.awt.Point;
-import java.awt.image.DataBuffer;
-import java.awt.image.WritableRaster;
-import java.util.Map;
-
-import javax.media.jai.PlanarImage;
-import javax.media.jai.RasterFactory;
-
-import org.geotools.coverage.GridSampleDimension;
-import org.geotools.coverage.grid.GridCoverage2D;
-import org.geotools.coverage.grid.GridCoverageFactory;
-import org.geotools.coverage.grid.GridGeometry2D;
-import org.geotools.geometry.Envelope2D;
-import org.opengis.coverage.grid.GridCoverage;
-
-import schmitzm.data.WritableGrid;
-
-/**
- * Diese Klasse stellt ein {@linkplain GridCoverage2D GeoTools-GridCoverage} (2D) dar,
- * welches auf einem {@link WritableRaster} basiert und darauf direkten
- * Lese- und Schreibzugriff liefert.<br>
- * Auch wenn {@link WritableRaster} prinzipell mehrere Dimensionen (Baender)
- * zulaesst, sind die Zugriffsmethoden dieser Klasse auf ein Band beschraenkt.<br>
- * <br>
- * <br>Um Instanzen dieser Klasse zu erzeugen, sollten die Factory-Methoden
- * {@code create(.)} verwendet werden!</b>
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class WritableGridCoverage extends ReadableGridCoverage implements WritableGrid {
-  /**
-   * Speichert die Datenbasis des Grids als {@link WritableRaster}.
-   * Entspricht {@link ReadableGridCoverage#raster}.
-   */
-  protected WritableRaster writableRaster = null;
-
-  /**
-   * Ruft den Standard-Konstruktor der von {@link GridCoverage2D} auf.
-   * @param name          Name des Grids
-   * @param image         Image-Daten (muss ein {@link WritableRaster} beinhalten)
-   * @param gridGeometry  Georeferenz und CRS
-   * @param bands         Sample-Dimensions fuer jedes Band (kann {@code null} sein)
-   * @param sources       Quell-Grids (kann {@code null} sein
-   * @param properties    Properties fuer das Grid (kann {@code null} sein)
-   * @param band          Band der Datenbasis, auf das die getter/setter referenziert sind
-   */
-  protected WritableGridCoverage(CharSequence name, PlanarImage image, GridGeometry2D gridGeometry, GridSampleDimension[] bands, GridCoverage[] sources, Map properties, int band) {
-    super( name, image, gridGeometry, bands, sources, properties, band );
-    if ( !(raster instanceof WritableRaster) )
-      throw new UnsupportedOperationException("Image for WritableGridCoverage mus provide a WritableRaster!");
-    this.writableRaster = (WritableRaster)raster;
-  }
-
-  /**
-   * Erzeugt ein neues Grid.
-   * @param gc   Datenbasis fuer das Grid
-   * @param band Band der Datenbasis, auf das die getter/setter referenziert sind
-   */
-  public static WritableGridCoverage create(GridCoverage2D gc, int band) {
-    return new WritableGridCoverage(
-      gc.getName().toString(),
-      PlanarImage.wrapRenderedImage(gc.getRenderedImage()),
-      (GridGeometry2D)gc.getGridGeometry(),
-      gc.getSampleDimensions(),
-      null,
-      null,
-      band
-    );
-  }
-
-  /**
-   * Erzeugt ein neues Grid.
-   * @param name     Name fuer das Grid
-   * @param raster   Datenbasis fuer das Grid
-   * @param band     Band der Datenbasis, auf das referenziert wird
-   * @param envelope GeoReferenz fuer das Raster
-   */
-  public static WritableGridCoverage create(String name, WritableRaster raster, int band, Envelope2D envelope) {
-    return create( new GridCoverageFactory().create(name,raster,envelope), band  );
-  }
-
-  /**
-   * Erzeugt ein neues Grid. Die Spalten sind von 0 bis <code>w-1</code>, die
-   * Zeilen von 0 bis <code>h-1</code> durchnummeriert.
-   * @param name     Name fuer das Grid
-   * @param type     Datentyp, der im Raster gespeichert ist (z.B. {@link DataBuffer#TYPE_INT})
-   * @param w        Breite des Rasters in Zellen
-   * @param h        Hoehe des Rasters in Zellen
-   * @param envelope GeoReferenz fuer das Raster
-   */
-  public static WritableGridCoverage create(String name, int type, int w, int h, Envelope2D envelope) {
-    return create(name,type,w,h,0,0,envelope);
-  }
-
-  /**
-   * Erzeugt ein neues Grid.
-   * @param name     Name fuer das Grid
-   * @param type     Datentyp, der im Raster gespeichert ist (z.B. {@link DataBuffer#TYPE_INT})
-   * @param w        Breite des Rasters in Zellen
-   * @param h        Hoehe des Rasters in Zellen
-   * @param x0       Index, mit dem die linke Spalte des Rasters angesprochen wird
-   * @param y0       Index, mit dem die oberste Zeile des Rasters angesprochen wird
-   * @param envelope GeoReferenz fuer das Raster
-   */
-  public static WritableGridCoverage create(String name, int type, int w, int h, int x0, int y0, Envelope2D envelope) {
-    return create(name,RasterFactory.createBandedRaster(type,w,h,1,new Point(x0,y0)), envelope);
-  }
-
-  /**
-   * Erzeugt ein neues Grid. Es wird automatisch auf Band 0 des WritableRasters
-   * Bezug genommen.
-   * @param name     Name fuer das Grid
-   * @param raster   Datenbasis fuer das Grid
-   * @param envelope GeoReferenz fuer das Raster
-   */
-  public static WritableGridCoverage create(String name, WritableRaster raster, Envelope2D envelope) {
-    return create(name,raster,0,envelope);
-  }
-
-//  /**
-//   * Erzeugt eine neue Instanz, basierend auf dem aktuellen Raster.
-//   * @deprecated Methode dient nur als Test/Notloesung und wird (hoffentlich)
-//   *             bald wieder entfernt werden koennen!
-//   */
-//  public WritableGridCoverage createNew() {
-////    return new WritableGridCoverage(this.getName().toString(),raster,envelope);
-//    return create(this.getName().toString(),raster,envelope);
-//  }
-
-  /**
-   * Liefert eine direkte Referenz auf die Datenbasis.
-   */
-  public WritableRaster getRaster() {
-    return writableRaster;
-  }
-
-  /**
-   * Setzt einen Wert im Raster ueber Raster-Koordinaten.
-   * @param value neuer Wert
-   * @param cell  2D-Raster-Koordinate (Zellenindizes, beginnend bei
-   *              {@link #getMinX()} und {@link #getMinY()})
-   * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
-   *            Koordinaten angegeben werden
-   */
-  public void setRasterSample(Object value, int... cell) {
-    if ( cell.length < RASTER_DIM )
-      throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
-//    // Bei 'raster' (WritableRaster) beginnen die Raster-Koordinaten in der
-//    // linken oberen Ecke. Im Grid soll die Zaehlung jedoch in der linken unteren
-//    // Ecke beginnen -> Y-Koordinate umrechnen
-//    int x = cell[0];
-//    int y = getMinY() + getHeight()-1 - cell[1];
-    // Bei 'raster' (WritableRaster) beginnen die Raster-Koordinaten in der
-    // linken oberen Ecke. Im Grid soll es genauso sein!
-    int x = cell[0];
-    int y = cell[1];
-
-    switch ( getSampleType() ) {
-      case DataBuffer.TYPE_BYTE:
-      case DataBuffer.TYPE_SHORT:
-      case DataBuffer.TYPE_USHORT:
-      case DataBuffer.TYPE_INT: writableRaster.setSample(x,y,band,((Number)value).intValue());
-                                break;
-      case DataBuffer.TYPE_FLOAT: writableRaster.setSample(x,y,band,((Number)value).floatValue());
-                                  break;
-      case DataBuffer.TYPE_DOUBLE: writableRaster.setSample(x,y,band,((Number)value).doubleValue());
-                                   break;
-    }
-  }
-
-  /**
-   * Liefert einen Wert des Rasters ueber Geo-Koordinaten. Liegt der
-   * Koordinatenwert genau auf der Grenze zwischen zwei Rasterzellen, wird die
-   * naechst groessere Zelle gewaehlt (ausser die Grenze entspricht dem Raster-Rand!).
-   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
-   * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
-   *            Koordinaten angegeben werden
-   */
-  public void setGridSample(Object value, double... coord) {
-    if ( coord.length < RASTER_DIM )
-      throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
-    // Koordinaten umrechnen in Zellen-Index
-    int cellX = convertRealToRaster(coord[0],0);
-    int cellY = convertRealToRaster(coord[1],1);
-    setRasterSample(value,cellX,cellY);
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.grid;
+
+import java.awt.Point;
+import java.awt.image.DataBuffer;
+import java.awt.image.WritableRaster;
+import java.util.Map;
+
+import javax.media.jai.PlanarImage;
+import javax.media.jai.RasterFactory;
+
+import org.geotools.coverage.GridSampleDimension;
+import org.geotools.coverage.grid.GridCoverage2D;
+import org.geotools.coverage.grid.GridCoverageFactory;
+import org.geotools.coverage.grid.GridGeometry2D;
+import org.geotools.geometry.Envelope2D;
+import org.opengis.coverage.grid.GridCoverage;
+
+import schmitzm.data.WritableGrid;
+
+/**
+ * Diese Klasse stellt ein {@linkplain GridCoverage2D GeoTools-GridCoverage} (2D) dar,
+ * welches auf einem {@link WritableRaster} basiert und darauf direkten
+ * Lese- und Schreibzugriff liefert.<br>
+ * Auch wenn {@link WritableRaster} prinzipell mehrere Dimensionen (Baender)
+ * zulaesst, sind die Zugriffsmethoden dieser Klasse auf ein Band beschraenkt.<br>
+ * <br>
+ * <br>Um Instanzen dieser Klasse zu erzeugen, sollten die Factory-Methoden
+ * {@code create(.)} verwendet werden!</b>
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class WritableGridCoverage extends ReadableGridCoverage implements WritableGrid {
+  /**
+   * Speichert die Datenbasis des Grids als {@link WritableRaster}.
+   * Entspricht {@link ReadableGridCoverage#raster}.
+   */
+  protected WritableRaster writableRaster = null;
+
+  /**
+   * Ruft den Standard-Konstruktor der von {@link GridCoverage2D} auf.
+   * @param name          Name des Grids
+   * @param image         Image-Daten (muss ein {@link WritableRaster} beinhalten)
+   * @param gridGeometry  Georeferenz und CRS
+   * @param bands         Sample-Dimensions fuer jedes Band (kann {@code null} sein)
+   * @param sources       Quell-Grids (kann {@code null} sein
+   * @param properties    Properties fuer das Grid (kann {@code null} sein)
+   * @param band          Band der Datenbasis, auf das die getter/setter referenziert sind
+   */
+  protected WritableGridCoverage(CharSequence name, PlanarImage image, GridGeometry2D gridGeometry, GridSampleDimension[] bands, GridCoverage[] sources, Map properties, int band) {
+    super( name, image, gridGeometry, bands, sources, properties, band );
+    if ( !(raster instanceof WritableRaster) )
+      throw new UnsupportedOperationException("Image for WritableGridCoverage mus provide a WritableRaster!");
+    this.writableRaster = (WritableRaster)raster;
+  }
+
+  /**
+   * Erzeugt ein neues Grid.
+   * @param gc   Datenbasis fuer das Grid
+   * @param band Band der Datenbasis, auf das die getter/setter referenziert sind
+   */
+  public static WritableGridCoverage create(GridCoverage2D gc, int band) {
+    return new WritableGridCoverage(
+      gc.getName().toString(),
+      PlanarImage.wrapRenderedImage(gc.getRenderedImage()),
+      (GridGeometry2D)gc.getGridGeometry(),
+      gc.getSampleDimensions(),
+      null,
+      null,
+      band
+    );
+  }
+
+  /**
+   * Erzeugt ein neues Grid.
+   * @param name     Name fuer das Grid
+   * @param raster   Datenbasis fuer das Grid
+   * @param band     Band der Datenbasis, auf das referenziert wird
+   * @param envelope GeoReferenz fuer das Raster
+   */
+  public static WritableGridCoverage create(String name, WritableRaster raster, int band, Envelope2D envelope) {
+    return create( new GridCoverageFactory().create(name,raster,envelope), band  );
+  }
+
+  /**
+   * Erzeugt ein neues Grid. Die Spalten sind von 0 bis <code>w-1</code>, die
+   * Zeilen von 0 bis <code>h-1</code> durchnummeriert.
+   * @param name     Name fuer das Grid
+   * @param type     Datentyp, der im Raster gespeichert ist (z.B. {@link DataBuffer#TYPE_INT})
+   * @param w        Breite des Rasters in Zellen
+   * @param h        Hoehe des Rasters in Zellen
+   * @param envelope GeoReferenz fuer das Raster
+   */
+  public static WritableGridCoverage create(String name, int type, int w, int h, Envelope2D envelope) {
+    return create(name,type,w,h,0,0,envelope);
+  }
+
+  /**
+   * Erzeugt ein neues Grid.
+   * @param name     Name fuer das Grid
+   * @param type     Datentyp, der im Raster gespeichert ist (z.B. {@link DataBuffer#TYPE_INT})
+   * @param w        Breite des Rasters in Zellen
+   * @param h        Hoehe des Rasters in Zellen
+   * @param x0       Index, mit dem die linke Spalte des Rasters angesprochen wird
+   * @param y0       Index, mit dem die oberste Zeile des Rasters angesprochen wird
+   * @param envelope GeoReferenz fuer das Raster
+   */
+  public static WritableGridCoverage create(String name, int type, int w, int h, int x0, int y0, Envelope2D envelope) {
+    return create(name,RasterFactory.createBandedRaster(type,w,h,1,new Point(x0,y0)), envelope);
+  }
+
+  /**
+   * Erzeugt ein neues Grid. Es wird automatisch auf Band 0 des WritableRasters
+   * Bezug genommen.
+   * @param name     Name fuer das Grid
+   * @param raster   Datenbasis fuer das Grid
+   * @param envelope GeoReferenz fuer das Raster
+   */
+  public static WritableGridCoverage create(String name, WritableRaster raster, Envelope2D envelope) {
+    return create(name,raster,0,envelope);
+  }
+
+//  /**
+//   * Erzeugt eine neue Instanz, basierend auf dem aktuellen Raster.
+//   * @deprecated Methode dient nur als Test/Notloesung und wird (hoffentlich)
+//   *             bald wieder entfernt werden koennen!
+//   */
+//  public WritableGridCoverage createNew() {
+////    return new WritableGridCoverage(this.getName().toString(),raster,envelope);
+//    return create(this.getName().toString(),raster,envelope);
+//  }
+
+  /**
+   * Liefert eine direkte Referenz auf die Datenbasis.
+   */
+  public WritableRaster getRaster() {
+    return writableRaster;
+  }
+
+  /**
+   * Setzt einen Wert im Raster ueber Raster-Koordinaten.
+   * @param value neuer Wert
+   * @param cell  2D-Raster-Koordinate (Zellenindizes, beginnend bei
+   *              {@link #getMinX()} und {@link #getMinY()})
+   * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
+   *            Koordinaten angegeben werden
+   */
+  public void setRasterSample(Object value, int... cell) {
+    if ( cell.length < RASTER_DIM )
+      throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
+//    // Bei 'raster' (WritableRaster) beginnen die Raster-Koordinaten in der
+//    // linken oberen Ecke. Im Grid soll die Zaehlung jedoch in der linken unteren
+//    // Ecke beginnen -> Y-Koordinate umrechnen
+//    int x = cell[0];
+//    int y = getMinY() + getHeight()-1 - cell[1];
+    // Bei 'raster' (WritableRaster) beginnen die Raster-Koordinaten in der
+    // linken oberen Ecke. Im Grid soll es genauso sein!
+    int x = cell[0];
+    int y = cell[1];
+
+    switch ( getSampleType() ) {
+      case DataBuffer.TYPE_BYTE:
+      case DataBuffer.TYPE_SHORT:
+      case DataBuffer.TYPE_USHORT:
+      case DataBuffer.TYPE_INT: writableRaster.setSample(x,y,band,((Number)value).intValue());
+                                break;
+      case DataBuffer.TYPE_FLOAT: writableRaster.setSample(x,y,band,((Number)value).floatValue());
+                                  break;
+      case DataBuffer.TYPE_DOUBLE: writableRaster.setSample(x,y,band,((Number)value).doubleValue());
+                                   break;
+    }
+  }
+
+  /**
+   * Liefert einen Wert des Rasters ueber Geo-Koordinaten. Liegt der
+   * Koordinatenwert genau auf der Grenze zwischen zwei Rasterzellen, wird die
+   * naechst groessere Zelle gewaehlt (ausser die Grenze entspricht dem Raster-Rand!).
+   * @param coord  2D-Raster-Koordinate (Lat/Lon-GeoReferenz)
+   * @exception UnsupportedOperationException falls zu {@linkplain #RASTER_DIM wenig}
+   *            Koordinaten angegeben werden
+   */
+  public void setGridSample(Object value, double... coord) {
+    if ( coord.length < RASTER_DIM )
+      throw new UnsupportedOperationException(RASTER_DIM+" Coordinates expected");
+    // Koordinaten umrechnen in Zellen-Index
+    int cellX = convertRealToRaster(coord[0],0);
+    int cellY = convertRealToRaster(coord[1],1);
+    setRasterSample(value,cellX,cellY);
+  }
+}

Modified: trunk/src/schmitzm/geotools/gui/CRSSelectionDialog.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/CRSSelectionDialog.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/CRSSelectionDialog.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,455 +1,473 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.gui;
-
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.Frame;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.util.Map;
-import java.util.Set;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-import javax.swing.AbstractAction;
-import javax.swing.AbstractButton;
-import javax.swing.Action;
-import javax.swing.JButton;
-import javax.swing.JCheckBox;
-import javax.swing.JDialog;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JRadioButton;
-import javax.swing.JScrollPane;
-import javax.swing.JTextArea;
-
-import org.apache.log4j.Logger;
-import org.geotools.referencing.CRS;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-
-import schmitzm.geotools.GTUtil;
-import schmitzm.lang.LangUtil;
-import schmitzm.lang.ResourceProvider;
-import schmitzm.swing.ButtonGroup;
-import schmitzm.swing.ExceptionDialog;
-import schmitzm.swing.InputOption;
-import schmitzm.swing.JPanel;
-import schmitzm.swing.SelectionInputOption;
-import schmitzm.swing.StatusDialog;
-import schmitzm.swing.SwingUtil;
-import schmitzm.swing.SwingWorker;
-import schmitzm.swing.event.InputOptionAdapter;
-
-/**
- * Dieser Dialog stellt verschiedene {@link CoordinateReferenceSystem} (CRS)
- * zur Auswahl. Neben einer Auswahl von vordefinierten CRS, wird WGS-84, sowie
- * (optional) ein beliebiges Standard-CRS dargestellt. Zudem kann in einem
- * Text-Feld die WKT-Spezifikation manuell eingegeben oder editiert werden.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class CRSSelectionDialog extends JDialog {
-  private   Logger           LOGGER = LangUtil.createLogger(this);
-  private   ResourceProvider RES = GeotoolsGUIUtil.RESOURCE;
-
-  /** Beinhaltet die vordefinierten CRS. Die Map beinhaltet pro Authority eine
-   *  Map mit den CRS. */
-  protected static SortedMap<String,SortedMap<String,CoordinateReferenceSystem>> predefinedCRS = null;
-
-  /** Label in dem die Meldung angezeigt wird. */
-  protected JTextArea  messageLabel = null;
-  /** Radio-Button fuer das WGS84-CRS. */
-  protected JRadioButton wgs84Button = null;
-  /** Radio-Button fuer das Standard-CRS. */
-  protected JRadioButton defaultButton = null;
-  /** Radio-Button fuer ein vordefiniertes CRS. */
-  protected JRadioButton predefinedButton = null;
-  /** Auswahl-Feld fuer die Authority. */
-  protected SelectionInputOption.Combo<String> authoritySelect = null;
-  /** Auswahl-Feld fuer das Authority-CRS. */
-  protected SelectionInputOption.Combo<CoordinateReferenceSystem> crsSelect = null;
-  /** Radio-Button fuer ein benutzerdefiniertes CRS. */
-  protected JRadioButton userButton = null;
-  /** Gruppe der Auswahl-Buttons. */
-  protected ButtonGroup buttonGroup = null;
-  /** Bereich, in dem das CRS als WKT angezeigt wird. */
-  protected JTextArea wktTextArea = null;
-  /** ScrollPane, in dem sich die TextArea fuer die WKT-Definition befinden. */
-  protected JScrollPane wktScrollPane = null;
-
-  /** Die Checkbox "Immer diese Auswahl treffen" des Dialogs. */
-  protected JCheckBox rememberCheckbox = null;
-  /** Der OK-Button des Dialogs. */
-  protected JButton okButton = null;
-  /** Der Abbrechen-Button des Dialogs. */
-  protected JButton cancelButton = null;
-
-  /** Das als "Standard" angebotene CRS.  */
-  protected CoordinateReferenceSystem defaultCRS = null;
-  /** Das ausgewaehlte CRS.  */
-  protected CoordinateReferenceSystem selectedCRS = null;
-
-  /** Panel (mit {@link GridBagLayout}), in dem die Meldung und Radio-Buttons
-   *  angezeigt werden. */
-  protected JPanel contentPane = null;
-  /** Dem Dialog uebergeordnete Komponente. */
-  protected Component parent = null;
-
-  /**
-   * Erzeugt einen neuen Fehler-Dialog. Der Dialog wird relativ zum Parent-Fenster
-   * zentriert.
-   * @param parent         uebergeordnetes Fenster (kann <code>null</code> sein!)
-   * @param message        einleitende Meldung (kann <code>null</code> sein!)
-   * @param cancelAllowed  wenn {@code false}, kann der Dialog nicht abgebrochen werden
-   * @param rememberOption wenn {@code true} wird eine Checkbox "Immer diese Auswahl treffen"
-   *                       angezeigt
-   * @param defaultCRS     das als Standard angebotene CRS (kann {@code null} sein)
-   */
-  public CRSSelectionDialog(Component parent, String message, boolean cancelAllowed, boolean rememberOption, CoordinateReferenceSystem defaultCRS) {
-    super((Frame)null,true);
-    initPredefinedCRS();
-
-    this.defaultCRS     = defaultCRS;
-    this.parent         = parent;
-
-    // Vorlagen-Dialog erzeugen
-    if ( message != null ) {
-      this.messageLabel = new JTextArea();
-      this.messageLabel.setWrapStyleWord(true);
-      this.messageLabel.setFont( new JLabel().getFont() );
-      this.messageLabel.setBackground( new JLabel("").getBackground() );
-      this.messageLabel.setText(message);
-      this.messageLabel.setEditable(false);
-    }
-    this.wktTextArea      = new JTextArea(10,60);
-    this.wktTextArea.setWrapStyleWord(true);
-    this.wktScrollPane    = new JScrollPane(wktTextArea);
-    this.buttonGroup      = new ButtonGroup();
-    this.wgs84Button      = createRadioButton( RES.getString("schmitzm.geotools.gui.CRSSelectionDialog.button.wgs84") );
-    this.userButton       = createRadioButton( RES.getString("schmitzm.geotools.gui.CRSSelectionDialog.button.userDefined") );
-    this.predefinedButton = createRadioButton( RES.getString("schmitzm.geotools.gui.CRSSelectionDialog.button.predefined") );
-    if ( defaultCRS != null ) {
-      this.defaultButton = createRadioButton( RES.getString("schmitzm.geotools.gui.CRSSelectionDialog.button.default", defaultCRS.getName().toString()) );
-      this.defaultButton.setSelected(true);
-    } else
-      this.wgs84Button.setSelected(true);
-    this.crsSelect        = new SelectionInputOption.Combo<CoordinateReferenceSystem>(null,true);
-    this.authoritySelect  = new SelectionInputOption.Combo<String>(null,true);
-    this.authoritySelect.setSelectionObjects(predefinedCRS.keySet().toArray(), null);
-    this.authoritySelect.setSelectedItem(0);
-    SwingUtil.setPreferredWidth( this.authoritySelect, 100 );
-    SwingUtil.setMinimumWidth( this.authoritySelect, 100 );
-    // Wenn Authority geaendet wird, die CRS-Auswahl aktualisieren
-    this.authoritySelect.addInputOptionListener( new InputOptionAdapter() {
-      public void optionChanged(InputOption option, Object oldValue, Object newValue) {
-        Map<String, CoordinateReferenceSystem> crsMap = predefinedCRS.get((String)newValue);
-        crsSelect.setSelectionObjects(
-            crsMap.values().toArray(new CoordinateReferenceSystem[0]),
-            crsMap.keySet().toArray(new String[0])
-        );
-        // Das erste CRS auswaehlen
-        if ( crsSelect.getSelectedItemCount() > 0 )
-          crsSelect.setSelectedIndex(0);
-      }
-    });
-    // Wenn CRS geaendert wird, das WKT-Feld aktualisieren
-    this.crsSelect.addInputOptionListener( new InputOptionAdapter() {
-      public void optionChanged(InputOption option, Object oldValue, Object newValue) {
-        resetWKT( (CoordinateReferenceSystem)newValue );
-      }
-    });
-    // Wenn Authority vorhanden, die erste vorbelegen
-    if ( authoritySelect.getSelectedItemCount() > 0 )
-      authoritySelect.setSelectedIndex(0);
-
-    // Checkbox erstellen
-    if ( rememberOption )
-      this.rememberCheckbox = new JCheckBox( SwingUtil.RESOURCE.getString("RememberChoice") );
-
-    // Dialog-Button erstellen
-    this.okButton     = new JButton( SwingUtil.RESOURCE.getString("Ok") );
-    this.cancelButton = new JButton( SwingUtil.RESOURCE.getString("Cancel") );
-    this.cancelButton.addActionListener( new ActionListener() {
-      public void actionPerformed(ActionEvent e) {
-        performButton(cancelButton);
-      }
-    });
-    this.okButton.addActionListener( new ActionListener() {
-      public void actionPerformed(ActionEvent e) {
-        performButton(okButton);
-      }
-    } );
-
-    // GUI aufbauen
-    this.contentPane = new JPanel();
-    this.contentPane.setLayout( new GridBagLayout() );
-    if ( messageLabel != null )
-      this.contentPane.add(messageLabel, new GridBagConstraints(0,0,3,1,0.0,0.0,GridBagConstraints.WEST,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
-    this.contentPane.add(wgs84Button, new GridBagConstraints(0,1,3,1,0.0,0.0,GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
-    if ( defaultButton != null )
-      this.contentPane.add(defaultButton, new GridBagConstraints(0,2,3,1,0.0,0.0,GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
-    this.contentPane.add(predefinedButton, new GridBagConstraints(0,3,1,1,0.0,0.0,GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
-    this.contentPane.add(authoritySelect, new GridBagConstraints(1,3,1,1,0.0,0.0,GridBagConstraints.WEST,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
-    this.contentPane.add(crsSelect, new GridBagConstraints(2,3,1,1,1.0,0.0,GridBagConstraints.WEST,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
-    this.contentPane.add(userButton, new GridBagConstraints(0,4,3,1,0.0,0.0,GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
-    this.contentPane.add(wktScrollPane, new GridBagConstraints(0,5,3,1,1.0,1.0,GridBagConstraints.WEST,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
-    if ( rememberCheckbox != null )
-      this.contentPane.add(rememberCheckbox, new GridBagConstraints(0,6,3,1,0.0,0.0,GridBagConstraints.WEST,GridBagConstraints.HORIZONTAL,new Insets(0,0,0,0),0,0));
-
-    // Dialog erzeugen
-    JOptionPane  pane = new JOptionPane(
-      contentPane,
-      JOptionPane.QUESTION_MESSAGE,
-      JOptionPane.DEFAULT_OPTION,
-      null,
-      cancelAllowed ? new Object[] {okButton, cancelButton} : new Object[] { okButton }
-    );
-    JDialog dialog = pane.createDialog(parent,RES.getString("schmitzm.geotools.gui.CRSSelectionDialog.title"));
-
-    // Dialog nach Vorlage initialisieren
-    this.setDefaultCloseOperation( DO_NOTHING_ON_CLOSE );
-    this.setTitle( dialog.getTitle() );
-    this.getContentPane().setLayout(new BorderLayout());
-    this.getContentPane().add(dialog.getContentPane(), BorderLayout.CENTER);
-
-    // Sofern vorhanden, den Default-Button als Standard auswaehlen
-    performButton( defaultButton != null ? defaultButton : wgs84Button );
-
-    // Dialog in der Mitte des Parent-Fenster anordnen
-    pack();
-    SwingUtil.setRelativeFramePosition(this,SwingUtil.getParentWindow(parent),0.5,0.5);
-  }
-
-  /**
-   * Initialisiert die zur Verfuegung stehenden CRS.
-   */
-  protected void initPredefinedCRS() {
-    if ( predefinedCRS != null )
-      return;
-
-    // Initalisierung der CRS-Auswahl in einem SwingWorker
-    SwingWorker.Work work = new SwingWorker.Work() {
-      public TreeMap<String, SortedMap<String,CoordinateReferenceSystem>> execute() {
-        TreeMap<String, SortedMap<String,CoordinateReferenceSystem>> authorityCRS = new TreeMap<String,SortedMap<String,CoordinateReferenceSystem>>();
-        for ( String authority : (Set<String>)CRS.getSupportedAuthorities(true) ) {
-          SortedMap<String, CoordinateReferenceSystem> crs = GTUtil.getAvailableCRSByName(authority, false, true);
-          if ( !crs.isEmpty() )
-            authorityCRS.put(authority, crs);
-        }
-        return authorityCRS;
-      }
-      public void performError(Throwable err) {
-        if ( err instanceof ThreadDeath )
-          return;
-        super.performError(err);
-      }
-    };
-    SwingWorker worker = new SwingWorker(
-        work,
-        new StatusDialog(
-            parent,
-            RES.getString("schmitzm.geotools.gui.CRSSelectionDialog.init.crs.title"),
-            RES.getString("schmitzm.geotools.gui.CRSSelectionDialog.init.crs.mess")
-        )
-    );
-    try {
-      worker.start();
-    } catch (Exception err) {
-      // ignore this
-    }
-    predefinedCRS = (TreeMap<String, SortedMap<String,CoordinateReferenceSystem>>)worker.getWorkResult();
-    if ( predefinedCRS == null )
-      predefinedCRS = new TreeMap<String,SortedMap<String,CoordinateReferenceSystem>>();
-  }
-
-  /**
-   * Fuehrt die Aktion eines Buttons aus (Radio- oder Dialog-Button).
-   * @param button der aktivierte Button
-   */
-  protected void performButton(AbstractButton button) {
-    if ( button instanceof JRadioButton ) {
-      // Auswahl der Authority und des CRS nur aktiv, wenn Radio-Button
-      // fuer Authority ausgewaehlt ist
-      this.authoritySelect.setEnabled( button == predefinedButton );
-      this.crsSelect.setEnabled( button == predefinedButton );
-      // Benutzerdefinerte Eingabe nur aktiv, wenn der entsprechende
-      // Radio-Button ausgewaehlt ist
-      this.wktTextArea.setEnabled( button == userButton );
-    }
-
-    // Wenn Auswahl WGS84, Default oder Authority, dann das jeweilige WKT
-    // einblenden
-    if ( button == wgs84Button )
-      resetWKT( GTUtil.WGS84 );
-    if ( button == defaultButton )
-      resetWKT( defaultCRS );
-    if ( button == predefinedButton )
-      resetWKT( (CoordinateReferenceSystem)crsSelect.getValue() );
-    // Wenn Auswahl Benutzerdefiniert, dann direkt auf die WKT springen
-    if ( button == userButton )
-      wktTextArea.grabFocus();
-
-    // Abbrechen --> Dialog ohne CRS-Auswahl beenden
-    if ( button == cancelButton ) {
-      selectedCRS = null;
-      setVisible(false);
-    }
-    // OK --> Rueckgabe-CRS belegen
-    if ( button == okButton ) {
-      try {
-        selectedCRS = null;
-        if ( wgs84Button.isSelected() )
-          selectedCRS = GTUtil.WGS84;
-        if ( defaultButton != null && defaultButton.isSelected() )
-          selectedCRS = CRSSelectionDialog.this.defaultCRS;
-        if ( predefinedButton.isSelected() )
-          selectedCRS = (CoordinateReferenceSystem) crsSelect.getValue();
-        if ( userButton.isSelected() && !"".equals(wktTextArea.getText()) )
-          selectedCRS = CRS.parseWKT(wktTextArea.getText());
-        if ( selectedCRS == null )
-          JOptionPane.showMessageDialog(
-              this,
-              RES.getString("schmitzm.geotools.gui.CRSSelectionDialog.mandatory"),
-              RES.getString("schmitzm.geotools.gui.CRSSelectionDialog.title"),
-              JOptionPane.ERROR_MESSAGE
-          );
-        else
-          setVisible(false);
-      } catch (Exception err) {
-        selectedCRS = null;
-        ExceptionDialog.show(this, err);
-        // Nach Fehler zu der entsprechenden Komponente springen
-        if ( userButton.isSelected() )
-          wktTextArea.grabFocus();
-        else if ( predefinedButton.isSelected() )
-          predefinedButton.grabFocus();
-        else if ( buttonGroup.getSelectedButton() != null )
-          buttonGroup.getSelectedButton().grabFocus();
-      }
-    }
-  }
-
-  /**
-   * Erzeugt einen neuen Radio-Button und fuegt diesen in die {@link #buttonGroup} ein.
-   * @param label Label fuer den Radio-Button
-   */
-  protected JRadioButton createRadioButton(String label) {
-    Action action = new AbstractAction() {
-      public void actionPerformed(ActionEvent e) {
-        performButton( (AbstractButton)e.getSource() );
-      }
-    };
-    action.putValue(Action.SHORT_DESCRIPTION, label);
-    action.putValue(Action.LONG_DESCRIPTION, label);
-    action.putValue(Action.NAME, label);
-    JRadioButton button = new JRadioButton(action);
-    this.buttonGroup.add(button);
-    return button;
-  }
-
-  /**
-   * Belegt das WKT-Feld neu. Jedoch nur, wenn sich der Text aendert,
-   * damit nach Moeglichkeit die Caret-Position erhalten bleibt.
-   * @param crs darzustellendes CRS
-   */
-  protected void resetWKT(CoordinateReferenceSystem crs) {
-    String wkt = "";
-    try {
-      wkt = ( crs != null && crs.toWKT() != null ) ? crs.toWKT().toString() : "";
-    } catch (Exception err) {
-      LOGGER.warn(err.getMessage());
-    }
-
-    // Nur neu setzen, wenn auch Aenderung stattfindet (damit ggf.
-    // die Caret-Position erhalten bleibt)
-    if ( wktTextArea.getText() == null || !wktTextArea.getText().equals(wkt) ) {
-      wktTextArea.setText( wkt );
-      wktTextArea.setCaretPosition(0);
-    }
-  }
-
-  /**
-   * Liefert die angezeigte Meldung.
-   */
-  public String getMessage() {
-    return  messageLabel.getText();
-  }
-
-  /**
-   * Liefert den ausgewaehlen Radio-Button.
-   */
-  public AbstractButton getSelectedButton() {
-    return buttonGroup.getSelectedButton();
-  }
-
-  /**
-   * Prueft, ob der Dialog abgebrochen wurde.
-   */
-  public boolean isCanceled() {
-    return !isVisible() && getSelectedButton() == cancelButton;
-  }
-
-  /**
-   * Prueft, ob der Dialog via OK beendet wurde.
-   */
-  public boolean isConfirmed() {
-    return !isVisible() && getSelectedButton() == okButton;
-  }
-
-  /**
-   * Prueft, ob die "Immer diese Auswahl treffen" Option im Dialog
-   * angewaehlt ist.
-   * @return {@code false} solange der OK-Button noch nicht betaetigt wurde
-   */
-  public boolean isRememberOptionSet() {
-    return isConfirmed() && rememberCheckbox != null && rememberCheckbox.isSelected();
-  }
-
-  /**
-   * Liefert das ausgewaehlte CRS.
-   * @return {@code null} solange der OK-Button noch nicht betaetigt wurde
-   */
-  public CoordinateReferenceSystem getCRS() {
-    return this.selectedCRS;
-  }
-
-  /**
-   * Zeigt einen CRS-Auswahl-Dialog an.
-   * @param parent         uebergeordnetes Fenster (kann <code>null</code> sein!)
-   * @param message        einleitende Meldung (kann <code>null</code> sein!)
-   * @param cancelAllowed  wenn {@code false}, kann der Dialog nicht abgebrochen werden
-   * @param rememberOption wenn {@code true} wird eine Checkbox "Immer diese Auswahl treffen"
-   *                       angezeigt
-   * @param defaultCRS     das als Standard angebotene CRS (kann {@code null} sein)
-   */
-  public static CoordinateReferenceSystem show(Component parent, String message, boolean cancelAllowed, boolean alwaysOption, CoordinateReferenceSystem defaultCRS) {
-    CRSSelectionDialog dialog = new CRSSelectionDialog(parent,message,cancelAllowed,alwaysOption, defaultCRS);
-    dialog.setVisible(true);
-    return dialog.getCRS();
-  }
-
-  /**
-   * Zeigt einen CRS-Auswahl-Dialog an, der abgebrochen werden kann. Die Eigenschaft
-   * "immer diese Auswahl treffen" kann nicht eingestellt werden.
-   * @param parent         uebergeordnetes Fenster (kann <code>null</code> sein!)
-   * @param message        einleitende Meldung (kann <code>null</code> sein!)
-   * @param defaultCRS     das als Standard angebotene CRS (kann {@code null} sein)
-   * @see CRS#decode(String, boolean)
-   */
-  public static CoordinateReferenceSystem show(Component parent, String message, CoordinateReferenceSystem defaultCRS) {
-    return show(parent,message,true,false,defaultCRS);
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.gui;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Frame;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.Map;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import javax.swing.AbstractAction;
+import javax.swing.AbstractButton;
+import javax.swing.Action;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JRadioButton;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+
+import org.apache.log4j.Logger;
+import org.geotools.referencing.CRS;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+
+import schmitzm.geotools.GTUtil;
+import schmitzm.lang.LangUtil;
+import schmitzm.lang.ResourceProvider;
+import schmitzm.swing.ButtonGroup;
+import schmitzm.swing.ExceptionDialog;
+import schmitzm.swing.InputOption;
+import schmitzm.swing.JPanel;
+import schmitzm.swing.SelectionInputOption;
+import schmitzm.swing.StatusDialog;
+import schmitzm.swing.SwingUtil;
+import schmitzm.swing.SwingWorker;
+import schmitzm.swing.event.InputOptionAdapter;
+
+/**
+ * Dieser Dialog stellt verschiedene {@link CoordinateReferenceSystem} (CRS)
+ * zur Auswahl. Neben einer Auswahl von vordefinierten CRS, wird WGS-84, sowie
+ * (optional) ein beliebiges Standard-CRS dargestellt. Zudem kann in einem
+ * Text-Feld die WKT-Spezifikation manuell eingegeben oder editiert werden.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class CRSSelectionDialog extends JDialog {
+  private   Logger           LOGGER = LangUtil.createLogger(this);
+  private   ResourceProvider RES = GeotoolsGUIUtil.RESOURCE;
+
+  /** Beinhaltet die vordefinierten CRS. Die Map beinhaltet pro Authority eine
+   *  Map mit den CRS. */
+  protected static SortedMap<String,SortedMap<String,CoordinateReferenceSystem>> predefinedCRS = null;
+
+  /** Label in dem die Meldung angezeigt wird. */
+  protected JTextArea  messageLabel = null;
+  /** Radio-Button fuer das WGS84-CRS. */
+  protected JRadioButton wgs84Button = null;
+  /** Radio-Button fuer das Standard-CRS. */
+  protected JRadioButton defaultButton = null;
+  /** Radio-Button fuer ein vordefiniertes CRS. */
+  protected JRadioButton predefinedButton = null;
+  /** Auswahl-Feld fuer die Authority. */
+  protected SelectionInputOption.Combo<String> authoritySelect = null;
+  /** Auswahl-Feld fuer das Authority-CRS. */
+  protected SelectionInputOption.Combo<CoordinateReferenceSystem> crsSelect = null;
+  /** Radio-Button fuer ein benutzerdefiniertes CRS. */
+  protected JRadioButton userButton = null;
+  /** Gruppe der Auswahl-Buttons. */
+  protected ButtonGroup buttonGroup = null;
+  /** Bereich, in dem das CRS als WKT angezeigt wird. */
+  protected JTextArea wktTextArea = null;
+  /** ScrollPane, in dem sich die TextArea fuer die WKT-Definition befinden. */
+  protected JScrollPane wktScrollPane = null;
+
+  /** Die Checkbox "Immer diese Auswahl treffen" des Dialogs. */
+  protected JCheckBox rememberCheckbox = null;
+  /** Der OK-Button des Dialogs. */
+  protected JButton okButton = null;
+  /** Der Abbrechen-Button des Dialogs. */
+  protected JButton cancelButton = null;
+
+  /** Das als "Standard" angebotene CRS.  */
+  protected CoordinateReferenceSystem defaultCRS = null;
+  /** Das ausgewaehlte CRS.  */
+  protected CoordinateReferenceSystem selectedCRS = null;
+
+  /** Panel (mit {@link GridBagLayout}), in dem die Meldung und Radio-Buttons
+   *  angezeigt werden. */
+  protected JPanel contentPane = null;
+  /** Dem Dialog uebergeordnete Komponente. */
+  protected Component parent = null;
+
+  /**
+   * Erzeugt einen neuen Fehler-Dialog. Der Dialog wird relativ zum Parent-Fenster
+   * zentriert.
+   * @param parent         uebergeordnetes Fenster (kann <code>null</code> sein!)
+   * @param message        einleitende Meldung (kann <code>null</code> sein!)
+   * @param cancelAllowed  wenn {@code false}, kann der Dialog nicht abgebrochen werden
+   * @param rememberOption wenn {@code true} wird eine Checkbox "Immer diese Auswahl treffen"
+   *                       angezeigt
+   * @param defaultCRS     das als Standard angebotene CRS (kann {@code null} sein)
+   */
+  public CRSSelectionDialog(Component parent, String message, boolean cancelAllowed, boolean rememberOption, CoordinateReferenceSystem defaultCRS) {
+    super((Frame)null,true);
+    initPredefinedCRS();
+
+    this.defaultCRS     = defaultCRS;
+    this.parent         = parent;
+
+    // Vorlagen-Dialog erzeugen
+    if ( message != null ) {
+      this.messageLabel = new JTextArea();
+      this.messageLabel.setWrapStyleWord(true);
+      this.messageLabel.setFont( new JLabel().getFont() );
+      this.messageLabel.setBackground( new JLabel("").getBackground() );
+      this.messageLabel.setText(message);
+      this.messageLabel.setEditable(false);
+    }
+    this.wktTextArea      = new JTextArea(10,60);
+    this.wktTextArea.setWrapStyleWord(true);
+    this.wktScrollPane    = new JScrollPane(wktTextArea);
+    this.buttonGroup      = new ButtonGroup();
+    this.wgs84Button      = createRadioButton( RES.getString("schmitzm.geotools.gui.CRSSelectionDialog.button.wgs84") );
+    this.userButton       = createRadioButton( RES.getString("schmitzm.geotools.gui.CRSSelectionDialog.button.userDefined") );
+    this.predefinedButton = createRadioButton( RES.getString("schmitzm.geotools.gui.CRSSelectionDialog.button.predefined") );
+    if ( defaultCRS != null ) {
+      this.defaultButton = createRadioButton( RES.getString("schmitzm.geotools.gui.CRSSelectionDialog.button.default", defaultCRS.getName().toString()) );
+      this.defaultButton.setSelected(true);
+    } else
+      this.wgs84Button.setSelected(true);
+    this.crsSelect        = new SelectionInputOption.Combo<CoordinateReferenceSystem>(null,true);
+    this.authoritySelect  = new SelectionInputOption.Combo<String>(null,true);
+    this.authoritySelect.setSelectionObjects(predefinedCRS.keySet().toArray(), null);
+    this.authoritySelect.setSelectedItem(0);
+    SwingUtil.setPreferredWidth( this.authoritySelect, 100 );
+    SwingUtil.setMinimumWidth( this.authoritySelect, 100 );
+    // Wenn Authority geaendet wird, die CRS-Auswahl aktualisieren
+    this.authoritySelect.addInputOptionListener( new InputOptionAdapter() {
+      public void optionChanged(InputOption option, Object oldValue, Object newValue) {
+        Map<String, CoordinateReferenceSystem> crsMap = predefinedCRS.get((String)newValue);
+        crsSelect.setSelectionObjects(
+            crsMap.values().toArray(new CoordinateReferenceSystem[0]),
+            crsMap.keySet().toArray(new String[0])
+        );
+        // Das erste CRS auswaehlen
+        if ( crsSelect.getSelectedItemCount() > 0 )
+          crsSelect.setSelectedIndex(0);
+      }
+    });
+    // Wenn CRS geaendert wird, das WKT-Feld aktualisieren
+    this.crsSelect.addInputOptionListener( new InputOptionAdapter() {
+      public void optionChanged(InputOption option, Object oldValue, Object newValue) {
+        resetWKT( (CoordinateReferenceSystem)newValue );
+      }
+    });
+    // Wenn Authority vorhanden, die erste vorbelegen
+    if ( authoritySelect.getSelectedItemCount() > 0 )
+      authoritySelect.setSelectedIndex(0);
+
+    // Checkbox erstellen
+    if ( rememberOption )
+      this.rememberCheckbox = new JCheckBox( SwingUtil.RESOURCE.getString("RememberChoice") );
+
+    // Dialog-Button erstellen
+    this.okButton     = new JButton( SwingUtil.RESOURCE.getString("Ok") );
+    this.cancelButton = new JButton( SwingUtil.RESOURCE.getString("Cancel") );
+    this.cancelButton.addActionListener( new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        performButton(cancelButton);
+      }
+    });
+    this.okButton.addActionListener( new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        performButton(okButton);
+      }
+    } );
+
+    // GUI aufbauen
+    this.contentPane = new JPanel();
+    this.contentPane.setLayout( new GridBagLayout() );
+    if ( messageLabel != null )
+      this.contentPane.add(messageLabel, new GridBagConstraints(0,0,3,1,0.0,0.0,GridBagConstraints.WEST,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
+    this.contentPane.add(wgs84Button, new GridBagConstraints(0,1,3,1,0.0,0.0,GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
+    if ( defaultButton != null )
+      this.contentPane.add(defaultButton, new GridBagConstraints(0,2,3,1,0.0,0.0,GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
+    this.contentPane.add(predefinedButton, new GridBagConstraints(0,3,1,1,0.0,0.0,GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
+    this.contentPane.add(authoritySelect, new GridBagConstraints(1,3,1,1,0.0,0.0,GridBagConstraints.WEST,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
+    this.contentPane.add(crsSelect, new GridBagConstraints(2,3,1,1,1.0,0.0,GridBagConstraints.WEST,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
+    this.contentPane.add(userButton, new GridBagConstraints(0,4,3,1,0.0,0.0,GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
+    this.contentPane.add(wktScrollPane, new GridBagConstraints(0,5,3,1,1.0,1.0,GridBagConstraints.WEST,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
+    if ( rememberCheckbox != null )
+      this.contentPane.add(rememberCheckbox, new GridBagConstraints(0,6,3,1,0.0,0.0,GridBagConstraints.WEST,GridBagConstraints.HORIZONTAL,new Insets(0,0,0,0),0,0));
+
+    // Dialog erzeugen
+    JOptionPane  pane = new JOptionPane(
+      contentPane,
+      JOptionPane.QUESTION_MESSAGE,
+      JOptionPane.DEFAULT_OPTION,
+      null,
+      cancelAllowed ? new Object[] {okButton, cancelButton} : new Object[] { okButton }
+    );
+    JDialog dialog = pane.createDialog(parent,RES.getString("schmitzm.geotools.gui.CRSSelectionDialog.title"));
+
+    // Dialog nach Vorlage initialisieren
+    this.setDefaultCloseOperation( DO_NOTHING_ON_CLOSE );
+    this.setTitle( dialog.getTitle() );
+    this.getContentPane().setLayout(new BorderLayout());
+    this.getContentPane().add(dialog.getContentPane(), BorderLayout.CENTER);
+
+    // Sofern vorhanden, den Default-Button als Standard auswaehlen
+    performButton( defaultButton != null ? defaultButton : wgs84Button );
+
+    // Dialog in der Mitte des Parent-Fenster anordnen
+    pack();
+    SwingUtil.setRelativeFramePosition(this,SwingUtil.getParentWindow(parent),0.5,0.5);
+  }
+
+  /**
+   * Initialisiert die zur Verfuegung stehenden CRS.
+   */
+  protected void initPredefinedCRS() {
+    if ( predefinedCRS != null )
+      return;
+
+    // Initalisierung der CRS-Auswahl in einem SwingWorker
+    SwingWorker.Work work = new SwingWorker.Work() {
+      public TreeMap<String, SortedMap<String,CoordinateReferenceSystem>> execute() {
+        TreeMap<String, SortedMap<String,CoordinateReferenceSystem>> authorityCRS = new TreeMap<String,SortedMap<String,CoordinateReferenceSystem>>();
+        for ( String authority : (Set<String>)CRS.getSupportedAuthorities(true) ) {
+          SortedMap<String, CoordinateReferenceSystem> crs = GTUtil.getAvailableCRSByName(authority, false, true);
+          if ( !crs.isEmpty() )
+            authorityCRS.put(authority, crs);
+        }
+        return authorityCRS;
+      }
+      public void performError(Throwable err) {
+        if ( err instanceof ThreadDeath )
+          return;
+        super.performError(err);
+      }
+    };
+    SwingWorker worker = new SwingWorker(
+        work,
+        new StatusDialog(
+            parent,
+            RES.getString("schmitzm.geotools.gui.CRSSelectionDialog.init.crs.title"),
+            RES.getString("schmitzm.geotools.gui.CRSSelectionDialog.init.crs.mess")
+        )
+    );
+    try {
+      worker.start();
+    } catch (Exception err) {
+      // ignore this
+    }
+    predefinedCRS = (TreeMap<String, SortedMap<String,CoordinateReferenceSystem>>)worker.getWorkResult();
+    if ( predefinedCRS == null )
+      predefinedCRS = new TreeMap<String,SortedMap<String,CoordinateReferenceSystem>>();
+  }
+
+  /**
+   * Fuehrt die Aktion eines Buttons aus (Radio- oder Dialog-Button).
+   * @param button der aktivierte Button
+   */
+  protected void performButton(AbstractButton button) {
+    if ( button instanceof JRadioButton ) {
+      // Auswahl der Authority und des CRS nur aktiv, wenn Radio-Button
+      // fuer Authority ausgewaehlt ist
+      this.authoritySelect.setEnabled( button == predefinedButton );
+      this.crsSelect.setEnabled( button == predefinedButton );
+      // Benutzerdefinerte Eingabe nur aktiv, wenn der entsprechende
+      // Radio-Button ausgewaehlt ist
+      this.wktTextArea.setEnabled( button == userButton );
+    }
+
+    // Wenn Auswahl WGS84, Default oder Authority, dann das jeweilige WKT
+    // einblenden
+    if ( button == wgs84Button )
+      resetWKT( GTUtil.WGS84 );
+    if ( button == defaultButton )
+      resetWKT( defaultCRS );
+    if ( button == predefinedButton )
+      resetWKT( (CoordinateReferenceSystem)crsSelect.getValue() );
+    // Wenn Auswahl Benutzerdefiniert, dann direkt auf die WKT springen
+    if ( button == userButton )
+      wktTextArea.grabFocus();
+
+    // Abbrechen --> Dialog ohne CRS-Auswahl beenden
+    if ( button == cancelButton ) {
+      selectedCRS = null;
+      setVisible(false);
+    }
+    // OK --> Rueckgabe-CRS belegen
+    if ( button == okButton ) {
+      try {
+        selectedCRS = null;
+        if ( wgs84Button.isSelected() )
+          selectedCRS = GTUtil.WGS84;
+        if ( defaultButton != null && defaultButton.isSelected() )
+          selectedCRS = CRSSelectionDialog.this.defaultCRS;
+        if ( predefinedButton.isSelected() )
+          selectedCRS = (CoordinateReferenceSystem) crsSelect.getValue();
+        if ( userButton.isSelected() && !"".equals(wktTextArea.getText()) )
+          selectedCRS = CRS.parseWKT(wktTextArea.getText());
+        if ( selectedCRS == null )
+          JOptionPane.showMessageDialog(
+              this,
+              RES.getString("schmitzm.geotools.gui.CRSSelectionDialog.mandatory"),
+              RES.getString("schmitzm.geotools.gui.CRSSelectionDialog.title"),
+              JOptionPane.ERROR_MESSAGE
+          );
+        else
+          setVisible(false);
+      } catch (Exception err) {
+        selectedCRS = null;
+        ExceptionDialog.show(this, err);
+        // Nach Fehler zu der entsprechenden Komponente springen
+        if ( userButton.isSelected() )
+          wktTextArea.grabFocus();
+        else if ( predefinedButton.isSelected() )
+          predefinedButton.grabFocus();
+        else if ( buttonGroup.getSelectedButton() != null )
+          buttonGroup.getSelectedButton().grabFocus();
+      }
+    }
+  }
+
+  /**
+   * Erzeugt einen neuen Radio-Button und fuegt diesen in die {@link #buttonGroup} ein.
+   * @param label Label fuer den Radio-Button
+   */
+  protected JRadioButton createRadioButton(String label) {
+    Action action = new AbstractAction() {
+      public void actionPerformed(ActionEvent e) {
+        performButton( (AbstractButton)e.getSource() );
+      }
+    };
+    action.putValue(Action.SHORT_DESCRIPTION, label);
+    action.putValue(Action.LONG_DESCRIPTION, label);
+    action.putValue(Action.NAME, label);
+    JRadioButton button = new JRadioButton(action);
+    this.buttonGroup.add(button);
+    return button;
+  }
+
+  /**
+   * Belegt das WKT-Feld neu. Jedoch nur, wenn sich der Text aendert,
+   * damit nach Moeglichkeit die Caret-Position erhalten bleibt.
+   * @param crs darzustellendes CRS
+   */
+  protected void resetWKT(CoordinateReferenceSystem crs) {
+    String wkt = "";
+    try {
+      wkt = ( crs != null && crs.toWKT() != null ) ? crs.toWKT().toString() : "";
+    } catch (Exception err) {
+      LOGGER.warn(err.getMessage());
+    }
+
+    // Nur neu setzen, wenn auch Aenderung stattfindet (damit ggf.
+    // die Caret-Position erhalten bleibt)
+    if ( wktTextArea.getText() == null || !wktTextArea.getText().equals(wkt) ) {
+      wktTextArea.setText( wkt );
+      wktTextArea.setCaretPosition(0);
+    }
+  }
+
+  /**
+   * Liefert die angezeigte Meldung.
+   */
+  public String getMessage() {
+    return  messageLabel.getText();
+  }
+
+  /**
+   * Liefert den ausgewaehlen Radio-Button.
+   */
+  public AbstractButton getSelectedButton() {
+    return buttonGroup.getSelectedButton();
+  }
+
+  /**
+   * Prueft, ob der Dialog abgebrochen wurde.
+   */
+  public boolean isCanceled() {
+    return !isVisible() && getSelectedButton() == cancelButton;
+  }
+
+  /**
+   * Prueft, ob der Dialog via OK beendet wurde.
+   */
+  public boolean isConfirmed() {
+    return !isVisible() && getSelectedButton() == okButton;
+  }
+
+  /**
+   * Prueft, ob die "Immer diese Auswahl treffen" Option im Dialog
+   * angewaehlt ist.
+   * @return {@code false} solange der OK-Button noch nicht betaetigt wurde
+   */
+  public boolean isRememberOptionSet() {
+    return isConfirmed() && rememberCheckbox != null && rememberCheckbox.isSelected();
+  }
+
+  /**
+   * Liefert das ausgewaehlte CRS.
+   * @return {@code null} solange der OK-Button noch nicht betaetigt wurde
+   */
+  public CoordinateReferenceSystem getCRS() {
+    return this.selectedCRS;
+  }
+
+  /**
+   * Zeigt einen CRS-Auswahl-Dialog an.
+   * @param parent         uebergeordnetes Fenster (kann <code>null</code> sein!)
+   * @param message        einleitende Meldung (kann <code>null</code> sein!)
+   * @param cancelAllowed  wenn {@code false}, kann der Dialog nicht abgebrochen werden
+   * @param rememberOption wenn {@code true} wird eine Checkbox "Immer diese Auswahl treffen"
+   *                       angezeigt
+   * @param defaultCRS     das als Standard angebotene CRS (kann {@code null} sein)
+   */
+  public static CoordinateReferenceSystem show(Component parent, String message, boolean cancelAllowed, boolean alwaysOption, CoordinateReferenceSystem defaultCRS) {
+    CRSSelectionDialog dialog = new CRSSelectionDialog(parent,message,cancelAllowed,alwaysOption, defaultCRS);
+    dialog.setVisible(true);
+    return dialog.getCRS();
+  }
+
+  /**
+   * Zeigt einen CRS-Auswahl-Dialog an, der abgebrochen werden kann. Die Eigenschaft
+   * "immer diese Auswahl treffen" kann nicht eingestellt werden.
+   * @param parent         uebergeordnetes Fenster (kann <code>null</code> sein!)
+   * @param message        einleitende Meldung (kann <code>null</code> sein!)
+   * @param defaultCRS     das als Standard angebotene CRS (kann {@code null} sein)
+   * @see CRS#decode(String, boolean)
+   */
+  public static CoordinateReferenceSystem show(Component parent, String message, CoordinateReferenceSystem defaultCRS) {
+    return show(parent,message,true,false,defaultCRS);
+  }
+}

Modified: trunk/src/schmitzm/geotools/gui/ColorMapTable.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/ColorMapTable.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/ColorMapTable.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,289 +1,307 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.gui;
-
-import java.awt.Color;
-import java.util.Map;
-
-import javax.swing.JColorChooser;
-
-import org.geotools.styling.ColorMap;
-import org.geotools.styling.ColorMapEntry;
-import org.geotools.styling.ColorMapImpl;
-
-import schmitzm.geotools.styling.StylingUtil;
-import schmitzm.swing.CaptionsChangeable;
-import schmitzm.swing.table.AbstractMutableTableModel;
-import schmitzm.swing.table.ColorRenderer;
-import schmitzm.swing.table.MutableTable;
-
-/**
- * Diese Klasse stellt eine Tabelle dar, in der eine {@link ColorMap} dargestellt
- * und veraendert werden kann.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of  Bonn/Germany)
- * @version 1.0
- */
-public class ColorMapTable extends MutableTable implements CaptionsChangeable {
-    /** Key, um den 1. Tabellenkopf-Eintrag "Quantity" in der {@link CaptionsChangeable}-Map anzusprechen.
-     *  @see #resetCaptions(Map)*/
-  public static final String TABLEHEADER_QUANTITY = ColorMapTable.class.getName()+".Header.QUANTITY";
-  /** Key, um den 2. Tabellenkopf-Eintrag "Color" in der {@link CaptionsChangeable}-Map anzusprechen.
-   *  @see #resetCaptions(Map)*/
-  public static final String TABLEHEADER_COLOR = ColorMapTable.class.getName()+".Header.COLOR";
-  /** Key, um den 3. Tabellenkopf-Eintrag "Label" in der {@link CaptionsChangeable}-Map anzusprechen.
-   *  @see #resetCaptions(Map)*/
-  public static final String TABLEHEADER_LABEL = ColorMapTable.class.getName()+".Header.LABEL";
-
-  /**
-   * Erzeugt eine neue Tabelle
-   * @param colorMap darzustellende Farb-Palette
-   */
-  public ColorMapTable(ColorMap colorMap) {
-    super( new ColorMapTableModel(colorMap), MutableTable.ITEM_ADD | MutableTable.ITEM_REMOVE );
-    ((ColorMapTableModel)getModel()).table = this;
-    this.setDefaultRenderer(Color.class, new ColorRenderer(true));
-    this.setCellSelectionEnabled(true);
-  }
-
-  /**
-   * Erzeugt eine neue Tabelle. Die dargestellte Farb-Palette muss anschliessend
-   * noch mit {@link #setColorMap(ColorMap)} gesetzt werden.
-   */
-  public ColorMapTable() {
-    this(null);
-  }
-
-  /**
-   * Ruft {@link #performChange()} auf, auch wenn die CHANGE-Option nicht
-   * aktiviert ist.
-   */
-  public void performDoubleClick() {
-    performChange();
-  }
-
-  /**
-   * Liefert die in der Tabelle dargestelle Farb-Palette.
-   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-   */
-  public ColorMap getColorMap() {
-	  //return StylingUtil.clearColorMapLabels(  ((ColorMapTableModel)getModel()).colMap  );
-    return ((ColorMapTableModel)getModel()).colMap;
-  }
-
-  /**
-   * Setzt die in der Tabelle dargestelle Farb-Palette.
-   * @param colorMap darzustellende Farb-Palette
-   */
-  public void setColorMap(ColorMap colorMap) {
-    ((ColorMapTableModel)getModel()).colMap = colorMap;
-    ((ColorMapTableModel)getModel()).fireTableDataChanged();
-  }
-
-  /**
-   * Setzt die Bezeichnungen des Tabellenheaders neu.
-   * @param captionMap Map mit neuen Bezeichnungen fuer Headers
-   */
-  public void resetCaptions(Map<String,Object> captionMap) {
-    String[] header =  ((ColorMapTableModel)getModel()).createColumnNames();
-
-    Object caption = captionMap.get( TABLEHEADER_QUANTITY );
-    if ( caption != null )
-      header[0] = caption.toString();
-    caption = captionMap.get( TABLEHEADER_COLOR );
-    if ( caption != null )
-      header[1] = caption.toString();
-    caption = captionMap.get( TABLEHEADER_LABEL );
-    if ( caption != null )
-      header[2] = caption.toString();
-
-    ((ColorMapTableModel)getModel()).fireTableStructureChanged();
-  }
-
-  /**
-   * Diese Klasse stellt ein Daten-Modell fuer die Farbpaletten-Tabelle
-   * dar.
-   */
-  private static class ColorMapTableModel extends AbstractMutableTableModel {
-    protected MutableTable table   = null;
-    protected ColorMap     colMap   = null;
-    protected Class[]      colClass = new Class[]  {String.class, Color.class, String.class};
-
-    /**
-     * Erzeugt ein neues TableModel.
-     * @param colorMap Farb-Palette
-     */
-    public ColorMapTableModel(ColorMap colorMap) {
-      super();
-      this.colMap = colorMap;
-    }
-
-    /**
-     * Liefert die Spaltennamen der Tabelle.
-     */
-    @Override
-    public String[] createColumnNames() {
-      return new String[] {
-          GeotoolsGUIUtil.RESOURCE.getString(TABLEHEADER_QUANTITY),
-          GeotoolsGUIUtil.RESOURCE.getString(TABLEHEADER_COLOR),
-          GeotoolsGUIUtil.RESOURCE.getString(TABLEHEADER_LABEL)
-      };
-    }
-
-    /**
-     * Fuer Spalte 1 wird ein Farb-Dialog aufgerufen. Spalte 0 (Wert) und 2
-     * werden direkt in der Tabelle geaendert.
-     * @param row Zeilennummer (beginnend bei 0)
-     * @param col Spaltennummer (beginnend bei 0)
-     */
-    public void performChangeData(int row, int col) {
-      if ( col != 1 )
-        return;
-      ColorMapEntry entry = colMap.getColorMapEntry(row);
-      Color color = JColorChooser.showDialog(table,"Choose color",StylingUtil.getColorFromColorMapEntry(entry));
-      if ( color != null )
-        entry.setColor( StylingUtil.STYLE_BUILDER.colorExpression(color) );
-      //changeColorMapEntry( colMap.getColorMapEntry(row) );
-    }
-
-    /**
-     * Loescht einen Eintrag aus der Farb-Palette.
-     * @param row Zeilennummer (beginnend bei 0)
-     */
-    public void performRemoveRow(int row) {
-      ColorMapEntry[] entry = colMap.getColorMapEntries();
-      colMap = new ColorMapImpl();
-      for (int i=0; i<entry.length; i++)
-        if ( i != row )
-          colMap.addColorMapEntry(entry[i]);
-    }
-
-    /**
-     * Ruft einen Dialog auf, in dem ein neuer Wert und eine neue Farbe
-     * angegeben werden kann.
-     */
-    public void performAddRow() {
-      colMap.addColorMapEntry( StylingUtil.createColorMapEntry("",0.0,Color.WHITE,1.0) );
-    }
-
-/*
-    private void changeColorMapEntry(ColorMapEntry oldEntry) {
-      // Default-Wert fuer den Dialog ist zunaechst der alte Eintrag
-      ColorMapEntry defaultEntry = oldEntry;
-      while (true) {
-        // Dialog anzeigen um Eintrag zu aendern/erzeugen
-        ColorMapEntry newEntry = null;
-        try {
-          newEntry = showColorMapEntryDialog(defaultEntry);
-        } catch (Exception err) {
-          ExceptionDialog.show(table,err,"Error","Color map entry incorrect!");
-          // nochmal versuchen (WHILE-Schleife fortfuehren)
-          continue;
-        }
-        // wenn Dialog abgebrochen wurde oder der Eintrag nicht
-        // geaendert wurde, wird nichts gemacht
-        if (newEntry == null || newEntry.equals(oldEntry))
-          break;
-
-        // Eintrag einfuegen
-        if ( oldEntry == null )
-          // neuen Eintrag am Ende einfuegen
-          colMap.addColorMapEntry( newEntry );
-        else {
-          // alte gegen neue Category ersetzen
-          oldEntry.setColor( newEntry.getColor() );
-          oldEntry.setQuantity( newEntry.getQuantity() );
-        }
-        this.fireTableDataChanged();
-        break;
-      }
-    }
-
-    private ColorMapEntry showColorMapEntryDialog(ColorMapEntry entry) throws Exception {
-      Double defValue = (entry != null) ? StylingUtil.getQuantityFromColorMapEntry(entry) : 0.0;
-      Color  defColor = (entry != null) ? StylingUtil.getColorFromColorMapEntry(entry) : null;
-
-      Object[] obj = MultipleOptionPane.showMultipleInputDialog(
-          table,
-          "New quantity and color",
-          new InputOption[] {
-            new ManualInputOption.Double("Quantity",true,defValue),
-            new ColorInputOption("Color",true,defColor)
-          }
-      );
-      // Dialog abgebrochen
-      if ( obj == null )
-        return null;
-      // Neuen Eintrag erzeugen
-      return StylingUtil.createColorMapEntry("",(Double)obj[0],(Color)obj[1],1.0);
-    }
-*/
-    /**
-     * Liefert die Anzahl an Tabellenzeilen.
-     */
-    public int getRowCount() {
-      if ( colMap == null )
-        return 0;
-      return colMap.getColorMapEntries().length;
-    }
-
-    /**
-     * Liefert den Typ einer Spalte.
-     * @param col Spaltennummer (beginnend mit 0)
-     */
-    public Class getColumnClass(int col) {
-      return colClass[col];
-    }
-
-    /**
-     * Spezifiert, ob eine Zelle editierbar ist.
-     * @param row Zeilennummer (beginnend bei 0)
-     * @param col Spaltennummer (beginnend bei 0)
-     * @return <code>true</code> fuer Spalte 0 und 2, sonst <code>false</code>
-     */
-    public boolean isCellEditable(int row, int col) {
-      return col == 0 || col == 2;
-    }
-
-    /**
-     * Liefert einen Wert der Tabelle
-     * @param row Zeilennummer (beginnend bei 0)
-     * @param col Spaltennummer (beginnend bei 0)
-     */
-    public Object getValueAt(int row, int col) {
-      switch( col ) {
-        case 0: return StylingUtil.getQuantityFromColorMapEntry( colMap.getColorMapEntry(row) );
-        case 1: return StylingUtil.getColorFromColorMapEntry( colMap.getColorMapEntry(row) );
-        case 2: return colMap.getColorMapEntry(row).getLabel();
-      }
-      return null;
-    }
-
-    /**
-     * Setzt einen Wert der Tabelle. Diese Methode macht nichts fuer Werte in
-     * Spalte 1.
-     * @param obj neuer Wert fuer die Zelle
-     * @param row Zeilennummer (beginnend bei 0)
-     * @param col Spaltennummer (beginnend bei 0)
-     */
-    public void setValueAt(Object obj, int row, int col) {
-      try {
-        switch( col ) {
-          case 0: colMap.getColorMapEntry(row).setQuantity( StylingUtil.STYLE_BUILDER.literalExpression(Double.parseDouble((String)obj)) );
-                  break;
-          case 2: colMap.getColorMapEntry(row).setLabel( (String)obj );
-                  break;
-        }
-      } catch (Exception err) {
-      }
-    }
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.gui;
+
+import java.awt.Color;
+import java.util.Map;
+
+import javax.swing.JColorChooser;
+
+import org.geotools.styling.ColorMap;
+import org.geotools.styling.ColorMapEntry;
+import org.geotools.styling.ColorMapImpl;
+
+import schmitzm.geotools.styling.StylingUtil;
+import schmitzm.swing.CaptionsChangeable;
+import schmitzm.swing.table.AbstractMutableTableModel;
+import schmitzm.swing.table.ColorRenderer;
+import schmitzm.swing.table.MutableTable;
+
+/**
+ * Diese Klasse stellt eine Tabelle dar, in der eine {@link ColorMap} dargestellt
+ * und veraendert werden kann.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of  Bonn/Germany)
+ * @version 1.0
+ */
+public class ColorMapTable extends MutableTable implements CaptionsChangeable {
+    /** Key, um den 1. Tabellenkopf-Eintrag "Quantity" in der {@link CaptionsChangeable}-Map anzusprechen.
+     *  @see #resetCaptions(Map)*/
+  public static final String TABLEHEADER_QUANTITY = ColorMapTable.class.getName()+".Header.QUANTITY";
+  /** Key, um den 2. Tabellenkopf-Eintrag "Color" in der {@link CaptionsChangeable}-Map anzusprechen.
+   *  @see #resetCaptions(Map)*/
+  public static final String TABLEHEADER_COLOR = ColorMapTable.class.getName()+".Header.COLOR";
+  /** Key, um den 3. Tabellenkopf-Eintrag "Label" in der {@link CaptionsChangeable}-Map anzusprechen.
+   *  @see #resetCaptions(Map)*/
+  public static final String TABLEHEADER_LABEL = ColorMapTable.class.getName()+".Header.LABEL";
+
+  /**
+   * Erzeugt eine neue Tabelle
+   * @param colorMap darzustellende Farb-Palette
+   */
+  public ColorMapTable(ColorMap colorMap) {
+    super( new ColorMapTableModel(colorMap), MutableTable.ITEM_ADD | MutableTable.ITEM_REMOVE );
+    ((ColorMapTableModel)getModel()).table = this;
+    this.setDefaultRenderer(Color.class, new ColorRenderer(true));
+    this.setCellSelectionEnabled(true);
+  }
+
+  /**
+   * Erzeugt eine neue Tabelle. Die dargestellte Farb-Palette muss anschliessend
+   * noch mit {@link #setColorMap(ColorMap)} gesetzt werden.
+   */
+  public ColorMapTable() {
+    this(null);
+  }
+
+  /**
+   * Ruft {@link #performChange()} auf, auch wenn die CHANGE-Option nicht
+   * aktiviert ist.
+   */
+  public void performDoubleClick() {
+    performChange();
+  }
+
+  /**
+   * Liefert die in der Tabelle dargestelle Farb-Palette.
+   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+   */
+  public ColorMap getColorMap() {
+	  //return StylingUtil.clearColorMapLabels(  ((ColorMapTableModel)getModel()).colMap  );
+    return ((ColorMapTableModel)getModel()).colMap;
+  }
+
+  /**
+   * Setzt die in der Tabelle dargestelle Farb-Palette.
+   * @param colorMap darzustellende Farb-Palette
+   */
+  public void setColorMap(ColorMap colorMap) {
+    ((ColorMapTableModel)getModel()).colMap = colorMap;
+    ((ColorMapTableModel)getModel()).fireTableDataChanged();
+  }
+
+  /**
+   * Setzt die Bezeichnungen des Tabellenheaders neu.
+   * @param captionMap Map mit neuen Bezeichnungen fuer Headers
+   */
+  public void resetCaptions(Map<String,Object> captionMap) {
+    String[] header =  ((ColorMapTableModel)getModel()).createColumnNames();
+
+    Object caption = captionMap.get( TABLEHEADER_QUANTITY );
+    if ( caption != null )
+      header[0] = caption.toString();
+    caption = captionMap.get( TABLEHEADER_COLOR );
+    if ( caption != null )
+      header[1] = caption.toString();
+    caption = captionMap.get( TABLEHEADER_LABEL );
+    if ( caption != null )
+      header[2] = caption.toString();
+
+    ((ColorMapTableModel)getModel()).fireTableStructureChanged();
+  }
+
+  /**
+   * Diese Klasse stellt ein Daten-Modell fuer die Farbpaletten-Tabelle
+   * dar.
+   */
+  private static class ColorMapTableModel extends AbstractMutableTableModel {
+    protected MutableTable table   = null;
+    protected ColorMap     colMap   = null;
+    protected Class[]      colClass = new Class[]  {String.class, Color.class, String.class};
+
+    /**
+     * Erzeugt ein neues TableModel.
+     * @param colorMap Farb-Palette
+     */
+    public ColorMapTableModel(ColorMap colorMap) {
+      super();
+      this.colMap = colorMap;
+    }
+
+    /**
+     * Liefert die Spaltennamen der Tabelle.
+     */
+    @Override
+    public String[] createColumnNames() {
+      return new String[] {
+          GeotoolsGUIUtil.RESOURCE.getString(TABLEHEADER_QUANTITY),
+          GeotoolsGUIUtil.RESOURCE.getString(TABLEHEADER_COLOR),
+          GeotoolsGUIUtil.RESOURCE.getString(TABLEHEADER_LABEL)
+      };
+    }
+
+    /**
+     * Fuer Spalte 1 wird ein Farb-Dialog aufgerufen. Spalte 0 (Wert) und 2
+     * werden direkt in der Tabelle geaendert.
+     * @param row Zeilennummer (beginnend bei 0)
+     * @param col Spaltennummer (beginnend bei 0)
+     */
+    public void performChangeData(int row, int col) {
+      if ( col != 1 )
+        return;
+      ColorMapEntry entry = colMap.getColorMapEntry(row);
+      Color color = JColorChooser.showDialog(table,"Choose color",StylingUtil.getColorFromColorMapEntry(entry));
+      if ( color != null )
+        entry.setColor( StylingUtil.STYLE_BUILDER.colorExpression(color) );
+      //changeColorMapEntry( colMap.getColorMapEntry(row) );
+    }
+
+    /**
+     * Loescht einen Eintrag aus der Farb-Palette.
+     * @param row Zeilennummer (beginnend bei 0)
+     */
+    public void performRemoveRow(int row) {
+      ColorMapEntry[] entry = colMap.getColorMapEntries();
+      colMap = new ColorMapImpl();
+      for (int i=0; i<entry.length; i++)
+        if ( i != row )
+          colMap.addColorMapEntry(entry[i]);
+    }
+
+    /**
+     * Ruft einen Dialog auf, in dem ein neuer Wert und eine neue Farbe
+     * angegeben werden kann.
+     */
+    public void performAddRow() {
+      colMap.addColorMapEntry( StylingUtil.createColorMapEntry("",0.0,Color.WHITE,1.0) );
+    }
+
+/*
+    private void changeColorMapEntry(ColorMapEntry oldEntry) {
+      // Default-Wert fuer den Dialog ist zunaechst der alte Eintrag
+      ColorMapEntry defaultEntry = oldEntry;
+      while (true) {
+        // Dialog anzeigen um Eintrag zu aendern/erzeugen
+        ColorMapEntry newEntry = null;
+        try {
+          newEntry = showColorMapEntryDialog(defaultEntry);
+        } catch (Exception err) {
+          ExceptionDialog.show(table,err,"Error","Color map entry incorrect!");
+          // nochmal versuchen (WHILE-Schleife fortfuehren)
+          continue;
+        }
+        // wenn Dialog abgebrochen wurde oder der Eintrag nicht
+        // geaendert wurde, wird nichts gemacht
+        if (newEntry == null || newEntry.equals(oldEntry))
+          break;
+
+        // Eintrag einfuegen
+        if ( oldEntry == null )
+          // neuen Eintrag am Ende einfuegen
+          colMap.addColorMapEntry( newEntry );
+        else {
+          // alte gegen neue Category ersetzen
+          oldEntry.setColor( newEntry.getColor() );
+          oldEntry.setQuantity( newEntry.getQuantity() );
+        }
+        this.fireTableDataChanged();
+        break;
+      }
+    }
+
+    private ColorMapEntry showColorMapEntryDialog(ColorMapEntry entry) throws Exception {
+      Double defValue = (entry != null) ? StylingUtil.getQuantityFromColorMapEntry(entry) : 0.0;
+      Color  defColor = (entry != null) ? StylingUtil.getColorFromColorMapEntry(entry) : null;
+
+      Object[] obj = MultipleOptionPane.showMultipleInputDialog(
+          table,
+          "New quantity and color",
+          new InputOption[] {
+            new ManualInputOption.Double("Quantity",true,defValue),
+            new ColorInputOption("Color",true,defColor)
+          }
+      );
+      // Dialog abgebrochen
+      if ( obj == null )
+        return null;
+      // Neuen Eintrag erzeugen
+      return StylingUtil.createColorMapEntry("",(Double)obj[0],(Color)obj[1],1.0);
+    }
+*/
+    /**
+     * Liefert die Anzahl an Tabellenzeilen.
+     */
+    public int getRowCount() {
+      if ( colMap == null )
+        return 0;
+      return colMap.getColorMapEntries().length;
+    }
+
+    /**
+     * Liefert den Typ einer Spalte.
+     * @param col Spaltennummer (beginnend mit 0)
+     */
+    public Class getColumnClass(int col) {
+      return colClass[col];
+    }
+
+    /**
+     * Spezifiert, ob eine Zelle editierbar ist.
+     * @param row Zeilennummer (beginnend bei 0)
+     * @param col Spaltennummer (beginnend bei 0)
+     * @return <code>true</code> fuer Spalte 0 und 2, sonst <code>false</code>
+     */
+    public boolean isCellEditable(int row, int col) {
+      return col == 0 || col == 2;
+    }
+
+    /**
+     * Liefert einen Wert der Tabelle
+     * @param row Zeilennummer (beginnend bei 0)
+     * @param col Spaltennummer (beginnend bei 0)
+     */
+    public Object getValueAt(int row, int col) {
+      switch( col ) {
+        case 0: return StylingUtil.getQuantityFromColorMapEntry( colMap.getColorMapEntry(row) );
+        case 1: return StylingUtil.getColorFromColorMapEntry( colMap.getColorMapEntry(row) );
+        case 2: return colMap.getColorMapEntry(row).getLabel();
+      }
+      return null;
+    }
+
+    /**
+     * Setzt einen Wert der Tabelle. Diese Methode macht nichts fuer Werte in
+     * Spalte 1.
+     * @param obj neuer Wert fuer die Zelle
+     * @param row Zeilennummer (beginnend bei 0)
+     * @param col Spaltennummer (beginnend bei 0)
+     */
+    public void setValueAt(Object obj, int row, int col) {
+      try {
+        switch( col ) {
+          case 0: colMap.getColorMapEntry(row).setQuantity( StylingUtil.STYLE_BUILDER.literalExpression(Double.parseDouble((String)obj)) );
+                  break;
+          case 2: colMap.getColorMapEntry(row).setLabel( (String)obj );
+                  break;
+        }
+      } catch (Exception err) {
+      }
+    }
+  }
+}

Modified: trunk/src/schmitzm/geotools/gui/FeatureCollectionFilterPanel.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/FeatureCollectionFilterPanel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/FeatureCollectionFilterPanel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,634 +1,653 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.geotools.gui;
-
-import java.awt.BorderLayout;
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.Font;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.util.Map;
-
-import javax.swing.BorderFactory;
-import javax.swing.JButton;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JTextField;
-import javax.swing.ListSelectionModel;
-import javax.swing.event.AncestorEvent;
-import javax.swing.event.AncestorListener;
-
-import org.apache.log4j.Logger;
-import org.geotools.feature.FeatureCollection;
-import org.geotools.map.DefaultMapLayer;
-import org.geotools.styling.Style;
-import org.opengis.filter.Filter;
-
-import schmitzm.geotools.feature.AttributeTypeFilter;
-import schmitzm.geotools.feature.FeatureOperationTree;
-import schmitzm.geotools.feature.FeatureOperationTreeFilter;
-import schmitzm.geotools.feature.FeatureOperationTreeParser;
-import schmitzm.geotools.styling.StylingUtil;
-import schmitzm.swing.ExceptionDialog;
-import schmitzm.swing.SwingUtil;
-
-/**
- * Diese Klasse stellt ein Panel zur Verfuegung, mit der ein
- * {@link FeatureOperationTreeFilter} in Form einer arithmetischen (und
- * boolschen) Formel erstellt werden kann. Neben den Komponenten zur
- * Definition/Eingabe des Filters enthaelt das Panel einen Vorschau-Bereich, in
- * dem eine {@link FeatureCollection} angezeigt wird, auf der der Filter
- * angewandt wird.
- * 
- * @see FeatureOperationTree
- * @see FeatureOperationTreeParser
- * @see FeatureOperationTreeFilter
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- *         (University of Bonn/Germany)
- * @version 1.0
- */
-public class FeatureCollectionFilterPanel extends FeatureFilterPanel {
-	static Logger LOGGER = Logger.getLogger(FeatureCollectionFilterPanel.class);
-	/**
-	 * Konstante fuer die Layout-Constraints des Vorschau-Bereich.
-	 * 
-	 * @see #layoutConstraints
-	 * @see #previewPanel
-	 */
-	public static final String PREVIEW_PANEL = FeatureCollectionFilterPanel.class
-			.getName()
-			+ "filterPreviewPanel";
-	/**
-	 * Konstante fuer die Layout-Constraints des Testen-Button.
-	 * 
-	 * @see #layoutConstraints
-	 * @see #resetCaptions(Map)
-	 * @see #testButton
-	 */
-	public static final String TEST_BUTTON = FeatureCollectionFilterPanel.class
-			.getName()
-			+ ".TestButton";
-	/**
-	 * Konstante fuer die Layout-Constraints des Testen-Button.
-	 * 
-	 * @see #layoutConstraints
-	 * @see #testButton
-	 */
-	public static final String TESTRESULT_LABEL = FeatureCollectionFilterPanel.class
-			.getName()
-			+ ".TestResultLabel";
-	/**
-	 * Konstante fuer die Layout-Constraints des Details-Button.
-	 * 
-	 * @see #layoutConstraints
-	 * @see #testResultDetails
-	 */
-	public static final String TESTRESULTDETAILS_BUTTON = FeatureCollectionFilterPanel.class
-			.getName()
-			+ ".TestResultDetailsButton";
-	/**
-	 * Konstante fuer den Tooltip des Details-Button.
-	 * 
-	 * @see #testResultDetails
-	 */
-	public static final String TESTRESULTDETAILS_TOOLTIP = FeatureCollectionFilterPanel.class
-			.getName()
-			+ ".TestResultDetailsToolTip";
-
-	/**
-	 * Constant for the BorderTitle of the results panel
-	 */
-	public static final String RESULTS_BORDER_TITLE = FeatureCollectionFilterPanel.class
-			.getName()
-			+ ".ResultsBorderTitle";
-
-	/**
-	 * Constant for the BorderTitle of the filter definition part
-	 */
-	public static final String FILER_DEFINITION_BORDER_TITLE = FeatureCollectionFilterPanel.class
-			.getName()
-			+ ".FilterDefinitionBorderTitle";
-	/**
-	 * Constant for the ToolTip of the preview mappane
-	 */
-	public static final String PREVIEW_MAPPANE_TOOLTIP = FeatureCollectionFilterPanel.class
-			.getName()
-			+ ".PreviewMapPaneToolTip";
-
-	/** Panel fuer Filter-Vorschau. */
-	private FeatureTablePane previewPanel = null;
-	/** Button zum Testen der Formel */
-	protected JButton testButton = null;
-	/** Label mit Ergebnis des Formel-Tests */
-	protected JLabel testResult = null;
-	/** Button fuer Details des Formel-Tests-Ergebnis */
-	protected JButton testResultDetails = null;
-
-	/** Speichert, ob im Vorschau-Panel eine grafische Anzeige erscheinen soll */
-	private boolean geomPrev = false;
-	/** Speichert, die FeatureCollection */
-	private FeatureCollection fullFeatureCollection = null;
-
-	/** Speichert den letzten Fehler in der Filter-Regel. */
-	protected Throwable testError = null;
-
-	/**
-	 * A Panel with a titled border that contains all buttons used to define the
-	 * filter
-	 */
-	protected JPanel defineFilterPanel;
-
-	/**
-	 * Erzeugt ein neues Panel.
-	 * 
-	 * @param fc
-	 *            definiert die zur Verfuegung gestellten Feature-Attribute
-	 * @param geomPrev
-	 *            bestimmt, ob ein Preview-Bereich angezeigt wird ({@code true})
-	 *            oder nicht ({@code false})
-	 * @see FeatureCollection#getSchema()
-	 */
-	public FeatureCollectionFilterPanel(FeatureCollection fc, boolean geomPrev) {
-		this(fc, geomPrev, true);
-	}
-
-	/**
-	 * Erzeugt ein neues Panel
-	 * 
-	 * @param fc
-	 *            definiert die zur Verfuegung gestellten Feature-Attribute
-	 * @param initGUI
-	 *            Flag, ob {@link #initGUI()} am Ende des Konstruktor aufgerufen
-	 *            werden soll (wenn {@code false} muss die explizit durch die
-	 *            Unterklasse erfolgen!)
-	 */
-	protected FeatureCollectionFilterPanel(FeatureCollection fc,
-			boolean geomPrev, boolean initGUI) {
-		super(fc.getSchema(), false);
-		this.geomPrev = geomPrev;
-
-		// Layout-Anordnung fuer GUI
-		layoutConstraints.get(ATTRIBUTE_TABLE).gridwidth = 3;
-		layoutConstraints.get(ATTRIBUTE_TABLE).weighty = 0.3;
-		layoutConstraints.get(RULE_TEXTFIELD).gridwidth = 2;
-		layoutConstraints.get(OPERATOR_COMBOBOX).gridx = 2;
-		layoutConstraints.put(TEST_BUTTON, new GridBagConstraints(0, 4, 1, 1,
-				0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE,
-				new Insets(5, 10, 10, 10), 0, 0));
-		layoutConstraints
-				.put(TESTRESULT_LABEL, new GridBagConstraints(1, 4, 2, 1, 1.0,
-						0.0, GridBagConstraints.WEST,
-						GridBagConstraints.HORIZONTAL,
-						new Insets(5, 10, 10, 10), 0, 0));
-		layoutConstraints.put(TESTRESULTDETAILS_BUTTON, new GridBagConstraints(
-				2, 4, 1, 1, 0, 0.0, GridBagConstraints.EAST,
-				GridBagConstraints.NONE, new Insets(5, 10, 10, 10), 0, 0));
-		layoutConstraints.put(PREVIEW_PANEL, new GridBagConstraints(0, 5, 3, 1,
-				0, 0.7, GridBagConstraints.CENTER, GridBagConstraints.BOTH,
-				new Insets(5, 10, 10, 10), 0, 0));
-
-		if (initGUI)
-			initGUI();
-
-		setFeatureCollection(fc);
-	}
-
-	/**
-	 * Initalisiert die GUI des Fensters. Der "Start-Button" der durch die
-	 * Oberklasse definiert wird, wird dabei aus dem Panel entfernt!
-	 */
-	protected void initGUI() {
-		super.initGUI();
-
-		// Button zum Testen des Filters
-		testButton = new JButton(GeotoolsGUIUtil.R(TEST_BUTTON));
-		testButton.addActionListener(new ActionListener() {
-			public void actionPerformed(ActionEvent e) {
-				performRuleTest();
-			}
-		});
-
-		// Button fuer Details des Test-Ergebnis
-		testResultDetails = new JButton(GeotoolsGUIUtil
-				.R(TESTRESULTDETAILS_BUTTON));
-		testResultDetails.setVisible(false);
-		testResultDetails.setToolTipText(GeotoolsGUIUtil
-				.R(TESTRESULTDETAILS_TOOLTIP));
-		testResultDetails.addActionListener(new ActionListener() {
-			public void actionPerformed(ActionEvent e) {
-				ExceptionDialog.show(FeatureCollectionFilterPanel.this,
-						testError, true);
-			}
-		});
-
-		// Label fuer Fehler-Meldungen
-		testResult = new JLabel("");
-		// Schrift: rot und fett
-		testResult.setForeground(Color.RED);
-		testResult.setFont(testResult.getFont().deriveFont(Font.BOLD));
-
-		if (getPreviewPanel() == null) {
-
-			setPreviewPanel(new FeatureTablePane(null, geomPrev) {
-
-				// In der Tabelle sollen einzelne Werte selektiert werden
-				// koennen
-				// und diese bei einem Doppelklick in die Formel uebernommen
-				// werden
-				@Override
-				protected void initGUI(boolean geomPreview) {
-					super.initGUI(geomPreview);
-
-					mapPane
-							.setToolTipText(GeotoolsGUIUtil
-									.R(FeatureCollectionFilterPanel.PREVIEW_MAPPANE_TOOLTIP));
-
-					// nur einzelne Zellen duerfen selektiert werden
-					featuresTable.setColumnSelectionAllowed(true);
-					featuresTable
-							.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-					// beim Klick auf eine Tabellenzelle, soll der Wert in die
-					// Formel
-					// uebernommen werden
-					featuresTable.addMouseListener(new MouseAdapter() {
-						public void mouseClicked(MouseEvent e) {
-							if (e.getButton() == MouseEvent.BUTTON1
-									&& e.getClickCount() == 2)
-
-								// * TODO SK: Might have to be changed to Sorted
-								// / RowModel stuff ....?!
-								insertValueInRule(featuresTable.getValueAt(
-										featuresTable.getSelectedRow(),
-										featuresTable.getSelectedColumn()));
-						}
-					});
-
-					// /*
-					// * Der TableModelListener aus super.initGUI() will bei
-					// einem
-					// * tableChanged event nur die selektieren anzeigen. In der
-					// * vorschau eines filters läuft das anders.
-					// */
-					// final int length =
-					// featuresTableModel.getTableModelListeners().length;
-					// if (length > 0)
-					// featuresTableModel
-					// .removeTableModelListener(featuresTableModel
-					// .getTableModelListeners()[length - 1]);
-					//
-					// // Wenn neue FeatureCollection gesetzt wird, alle
-					// Features
-					// // in Vorschau anzeigen.
-					// featuresTableModel
-					// .addTableModelListener(new TableModelListener() {
-					// public void tableChanged(TableModelEvent e) {
-					// showFeaturesInMap(getFeatureCollection());
-					// }
-					// });
-				}
-
-				// Im Vorschau-Panel sollen nicht die in der Tabelle selektieren
-				// Features angezeigt werden, sondern immer ALLE Features der
-				// Tabelle (also das Resultat des Filters)
-				@Override
-				public void performListSelection() {
-				}
-
-				@Override
-				/*
-				 * This method differs from the super-method! This method does
-				 * not care about selections in the table. It shows the complete
-				 * table (= paramter fc) as a selection on top of the complete
-				 * feature collection (which is rendered in gray).
-				 */
-				protected void showFeaturesInMap() {
-
-					if (getPreviewPanel() == null)
-						return;
-
-					FeatureCollection specialFeatureCollection = getFeatureCollection();
-
-					final FeatureCollection allFeatures = FeatureCollectionFilterPanel.this
-							.getFeatureCollection();
-
-					if (specialFeatureCollection != null && allFeatures != null)
-						LOGGER.debug("The result to show contains "
-								+ specialFeatureCollection.size()
-								+ " of total " + allFeatures.size());
-
-					if (getPreviewPanel().mapPane.getContext().getLayerCount() == 0) {
-
-						if (allFeatures != null) {
-							/**
-							 * Als unterstes layer sollen alle Features in grau
-							 * dargestellt werden. Dieses Layer soll nur einmal
-							 * eingefügt werden
-							 */
-							getPreviewPanel().mapPane.getContext().addLayer(
-									new DefaultMapLayer(allFeatures,
-											StylingUtil.createStyleSimple(
-													allFeatures,
-													Color.lightGray,
-													Color.darkGray)));
-
-							// This thows an exception... We have to move to GT
-							// filters i guess.
-							getPreviewPanel().mapPane.zoomTo(allFeatures);
-						}
-					}
-
-					if (specialFeatureCollection != null && allFeatures != null) {
-						/**
-						 * Der Inhalt der Tabelle soll in rot darüber gezeichnet
-						 * werden. Dieses layer wird jedes mal neu erstellt.
-						 */
-						if (getPreviewPanel().mapPane.getContext()
-								.getLayerCount() > 1)
-							getPreviewPanel().mapPane.getContext().removeLayer(
-									1);
-
-						// nur neues Layer erzeugen, wenn FeatureCollection
-						// NICHT leer (sonst Exception im StreamingRenderer!)
-						if (specialFeatureCollection.size() > 0)
-							getPreviewPanel().mapPane.getContext().addLayer(
-									new DefaultMapLayer(
-											specialFeatureCollection,
-											StylingUtil.createStyleSimple(
-													specialFeatureCollection,
-													Color.red, Color.white)));
-					}
-				}
-			});
-
-			// The PreviewPanel gets a Border saying what it is
-			getPreviewPanel().setBorder(
-					BorderFactory.createTitledBorder(GeotoolsGUIUtil
-							.R(RESULTS_BORDER_TITLE)));
-
-			// SwingUtil.setPreferredWidth(getPreviewPanel(), 600);
-		}
-		// Geometry-Attribute sollen nicht angezeigt werden
-		getPreviewPanel().setAttributeFilter(AttributeTypeFilter.NO_GEOMETRY);
-
-		SwingUtil.setPreferredHeight(getPreviewPanel(), 150);
-
-		/**
-		 * Move all the Components that have been added so far into a new panel
-		 * that has a nice border.
-		 */
-		defineFilterPanel = new JPanel(getLayout());
-		// SwingUtil.setPreferredWidth(defineFilterPanel, 600);
-		defineFilterPanel.setBorder(BorderFactory
-				.createTitledBorder(GeotoolsGUIUtil
-						.R(FILER_DEFINITION_BORDER_TITLE)));
-		GridBagLayout gpl = (GridBagLayout) getLayout();
-		for (Component c : getComponents()) {
-			defineFilterPanel.add(c, gpl.getConstraints(c));
-		}
-		removeAll(); // From the contentpane
-		setLayout(new BorderLayout());
-
-		// zusaetzliche Komponenten einfuegen
-		defineFilterPanel.add(testButton, layoutConstraints.get(TEST_BUTTON));
-		defineFilterPanel.add(testResultDetails, layoutConstraints
-				.get(TESTRESULTDETAILS_BUTTON));
-		defineFilterPanel.add(testResult, layoutConstraints
-				.get(TESTRESULT_LABEL));
-
-		add(defineFilterPanel, BorderLayout.NORTH);
-
-		add(getPreviewPanel(), BorderLayout.CENTER);
-
-		// listen to the moment, the panel is inserted into a frame
-		// and then set the TEST-Button the default button
-		addAncestorListener(new AncestorListener() {
-			@Override
-			public void ancestorAdded(AncestorEvent event) {
-				if (getRootPane() != null
-						&& getRootPane().getDefaultButton() == null)
-					getRootPane().setDefaultButton(testButton);
-
-			}
-
-			@Override
-			public void ancestorMoved(AncestorEvent event) {
-			}
-
-			@Override
-			public void ancestorRemoved(AncestorEvent event) {
-			}
-		});
-	}
-
-	/**
-	 * Setzt den Filter, der die dargestellten Attribute bestimmt.
-	 * 
-	 * @param attrFilter
-	 *            Filter
-	 */
-	public void setAttributeFilter(AttributeTypeFilter attrFilter) {
-		super.setAttributeFilter(attrFilter);
-		// Filter auch auf die in der Vorschau dargestellten
-		// Attribut-Spalten anwenden
-		getPreviewPanel().setAttributeFilter(attrFilter);
-	}
-
-	/**
-	 * Setzt die Labels des Panels neu.
-	 * 
-	 * @param captionMap
-	 *            Map
-	 * @see FeatureFilterPanel#resetCaptions(Map)
-	 */
-	public void resetCaptions(Map<String, Object> captionMap) {
-		super.resetCaptions(captionMap);
-		SwingUtil.resetCaption(testButton, captionMap.get(TEST_BUTTON));
-
-		/**
-		 * TODO ?! resteCaption doesn't handle BorderTitle yet
-		 * SwingUtil.resetCaption(defineFilterPanel.getBorder(),
-		 * captionMap.get(FILER_DEFINITION_BORDER_TITLE)); //
-		 * defineFilterPanel.setBorder(
-		 * BorderFactory.createTitledBorder(GeotoolsGUIUtil.RESOURCE //
-		 * .getString(FILER_DEFINITION_BORDER_TITLE)));
-		 */
-	}
-
-	/**
-	 * Fuegt an der Curserposition einen Wert in die Formel ein.
-	 * 
-	 * @param value
-	 *            Object
-	 */
-	protected void insertValueInRule(Object value) {
-		if (value == null)
-			value = "";
-
-		String ruleValue = value.toString();
-		// Nur numerische Werte direkt in Formel einfuegen.
-		// Andere Werte als String in Anfuehrungsstrichen gekapselt.
-		if (!(value instanceof Number))
-			ruleValue = "\"" + ruleValue + "\"";
-		// Wert in Formel einfuegen
-		performOperatorInsert(ruleValue, (JTextField) this.rule
-				.getInputComponent());
-		// Fokus zurueck auf Formel-Feld
-		rule.grabFocus();
-	}
-
-	/**
-	 * Setzt die aktuell im Dialog eingegebene Formel und aktualisiert die
-	 * Vorschau.
-	 * 
-	 * @param rule
-	 *            Formel als String
-	 */
-	public void setRule(String rule) {
-		super.setRule(rule);
-		performRuleTest();
-	}
-
-	/**
-	 * Wird ausgefuehrt, wenn der Testen-Button gedrueckt wird. Erzeugt einen
-	 * Filter aus der angegebenen Formel, wertet diese auf der
-	 * {@link FeatureCollection} aus und zeigt das Resultat im
-	 * {@linkplain #previewPanel Vorschau-Bereich} an. <br>
-	 * Tritt ein Fehler auf, wird die entsprechende Meldung im Label
-	 * {@link #testResult} (neben dem Button) angezeigt.
-	 * 
-	 */
-	protected void performRuleTest() {
-		try {
-			FeatureCollection subCollection = filterFeatureCollection();
-			getPreviewPanel().setFeatureCollection(subCollection);
-			resetComponentsAfterTest(null);
-		} catch (Exception err) {
-			getPreviewPanel().setFeatureCollection(null);
-			resetComponentsAfterTest(err);
-		}
-		rule.grabFocus();
-	}
-
-	/**
-	 * (De)aktiviert Label und Button fuer die Fehlermeldung entsprechend einer
-	 * etwaigen Fehlermeldung. Wird ausgefuehrt nachdem der "Test"-Button
-	 * geklickt wurde.
-	 * 
-	 * @param err
-	 *            Fehler (kann {@code null} sein)
-	 */
-	protected void resetComponentsAfterTest(Throwable err) {
-		testError = err;
-		testResult.setText(err != null ? err.getMessage() : "");
-		testResultDetails.setVisible(err != null);
-	}
-
-	/**
-	 * Setzt die {@link FeatureCollection}, die (gefiltert) in der Vorschau
-	 * angezeigt wird.
-	 * 
-	 * @param fc
-	 *            eine {@link FeatureCollection}, die zum Feature-Type (Schema)
-	 *            des Formel-Panels passt
-	 * @exception IllegalArgumentException
-	 *                falls die FeatureCollection nicht zum Schema des Panels
-	 *                passt
-	 * @see FeatureCollection#getSchema()
-	 */
-	public void setFeatureCollection(FeatureCollection fc) {
-		if (getFeatureType() == null)
-			setFeatureType(fc.getSchema());
-		if (!fc.getSchema().equals(getFeatureType()))
-			throw new IllegalArgumentException(
-					"FeatureCollection does not fit to schema of the panel!");
-		this.fullFeatureCollection = fc;
-
-		if (getPreviewPanel() != null) {
-			getPreviewPanel().setFeatureCollection(fc);
-		}
-	}
-
-	/**
-	 * Liefert die ungefilterte {@link FeatureCollection}, auf der gefiltert
-	 * wird.
-	 */
-	public FeatureCollection getFeatureCollection() {
-		return fullFeatureCollection;
-	}
-
-	/**
-	 * Setzt den Style, in dem die Features in der Vorschau dargestellt werden.
-	 * 
-	 * @param style
-	 *            Style fuer die Features
-	 */
-	public void setFeatureStyle(Style style) {
-		getPreviewPanel().setFeatureStyle(style);
-	}
-
-	/**
-	 * Liefert den Style, in dem die Features in der Vorschau dargestellt
-	 * werden.
-	 */
-	public Style getFeatureStyle() {
-		return getPreviewPanel().getFeatureStyle();
-	}
-
-	/**
-	 * Wendet die im Panel eingetragene Filter-Formel auf die
-	 * {@link FeatureCollection} des Vorschau-Fensters an und liefert die
-	 * entsprechende Sub-Collection.
-	 * 
-	 * @see FeatureCollection#subCollection(Filter)
-	 */
-	public FeatureCollection filterFeatureCollection() {
-		return getFeatureCollection().subCollection(createFilter());
-	}
-
-	/**
-	 * Wendet die im Panel eingetragene Filter-Formel auf eine
-	 * {@link FeatureCollection} and und liefert die entsprechende
-	 * Sub-Collection.
-	 * 
-	 * @see FeatureCollection#subCollection(Filter)
-	 */
-	public FeatureCollection filterFeatureCollection(FeatureCollection fc) {
-		return fc.subCollection(createFilter());
-	}
-
-	/**
-	 * Öffentliche Methode um die Belegung der Vorschaukomponente zu ändern.
-	 * Sollte vor dem Aufruf von {@link #initGUI()} gesetzt werden, da diese
-	 * Methode {@link #getPreviewPanel()} benutzt.
-	 * 
-	 * @param previewPanel
-	 *            Das zu setzende {@link FeatureTablePane} oder eine eigene
-	 *            Erweiterung
-	 * @author SK
-	 */
-	public void setPreviewPanel(FeatureTablePane previewPanel) {
-		this.previewPanel = previewPanel;
-	}
-
-	/**
-	 * Liefert die aktuell gesetzt Vorschaukomponente. Kann auch
-	 * <code>null</code> zurückgeben. Wir in {@link #initGUI()} verwendet.
-	 */
-	public FeatureTablePane getPreviewPanel() {
-		return previewPanel;
-	}
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.gui;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Font;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.Map;
+
+import javax.swing.BorderFactory;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.ListSelectionModel;
+import javax.swing.event.AncestorEvent;
+import javax.swing.event.AncestorListener;
+
+import org.apache.log4j.Logger;
+import org.geotools.feature.FeatureCollection;
+import org.geotools.map.DefaultMapLayer;
+import org.geotools.styling.Style;
+import org.opengis.filter.Filter;
+
+import schmitzm.geotools.feature.AttributeTypeFilter;
+import schmitzm.geotools.feature.FeatureOperationTree;
+import schmitzm.geotools.feature.FeatureOperationTreeFilter;
+import schmitzm.geotools.feature.FeatureOperationTreeParser;
+import schmitzm.geotools.styling.StylingUtil;
+import schmitzm.swing.ExceptionDialog;
+import schmitzm.swing.SwingUtil;
+
+/**
+ * Diese Klasse stellt ein Panel zur Verfuegung, mit der ein
+ * {@link FeatureOperationTreeFilter} in Form einer arithmetischen (und
+ * boolschen) Formel erstellt werden kann. Neben den Komponenten zur
+ * Definition/Eingabe des Filters enthaelt das Panel einen Vorschau-Bereich, in
+ * dem eine {@link FeatureCollection} angezeigt wird, auf der der Filter
+ * angewandt wird.
+ * 
+ * @see FeatureOperationTree
+ * @see FeatureOperationTreeParser
+ * @see FeatureOperationTreeFilter
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *         (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class FeatureCollectionFilterPanel extends FeatureFilterPanel {
+	static Logger LOGGER = Logger.getLogger(FeatureCollectionFilterPanel.class);
+	/**
+	 * Konstante fuer die Layout-Constraints des Vorschau-Bereich.
+	 * 
+	 * @see #layoutConstraints
+	 * @see #previewPanel
+	 */
+	public static final String PREVIEW_PANEL = FeatureCollectionFilterPanel.class
+			.getName()
+			+ "filterPreviewPanel";
+	/**
+	 * Konstante fuer die Layout-Constraints des Testen-Button.
+	 * 
+	 * @see #layoutConstraints
+	 * @see #resetCaptions(Map)
+	 * @see #testButton
+	 */
+	public static final String TEST_BUTTON = FeatureCollectionFilterPanel.class
+			.getName()
+			+ ".TestButton";
+	/**
+	 * Konstante fuer die Layout-Constraints des Testen-Button.
+	 * 
+	 * @see #layoutConstraints
+	 * @see #testButton
+	 */
+	public static final String TESTRESULT_LABEL = FeatureCollectionFilterPanel.class
+			.getName()
+			+ ".TestResultLabel";
+	/**
+	 * Konstante fuer die Layout-Constraints des Details-Button.
+	 * 
+	 * @see #layoutConstraints
+	 * @see #testResultDetails
+	 */
+	public static final String TESTRESULTDETAILS_BUTTON = FeatureCollectionFilterPanel.class
+			.getName()
+			+ ".TestResultDetailsButton";
+	/**
+	 * Konstante fuer den Tooltip des Details-Button.
+	 * 
+	 * @see #testResultDetails
+	 */
+	public static final String TESTRESULTDETAILS_TOOLTIP = FeatureCollectionFilterPanel.class
+			.getName()
+			+ ".TestResultDetailsToolTip";
+
+	/**
+	 * Constant for the BorderTitle of the results panel
+	 */
+	public static final String RESULTS_BORDER_TITLE = FeatureCollectionFilterPanel.class
+			.getName()
+			+ ".ResultsBorderTitle";
+
+	/**
+	 * Constant for the BorderTitle of the filter definition part
+	 */
+	public static final String FILER_DEFINITION_BORDER_TITLE = FeatureCollectionFilterPanel.class
+			.getName()
+			+ ".FilterDefinitionBorderTitle";
+	/**
+	 * Constant for the ToolTip of the preview mappane
+	 */
+	public static final String PREVIEW_MAPPANE_TOOLTIP = FeatureCollectionFilterPanel.class
+			.getName()
+			+ ".PreviewMapPaneToolTip";
+
+	/** Panel fuer Filter-Vorschau. */
+	private FeatureTablePane previewPanel = null;
+	/** Button zum Testen der Formel */
+	protected JButton testButton = null;
+	/** Label mit Ergebnis des Formel-Tests */
+	protected JLabel testResult = null;
+	/** Button fuer Details des Formel-Tests-Ergebnis */
+	protected JButton testResultDetails = null;
+
+	/** Speichert, ob im Vorschau-Panel eine grafische Anzeige erscheinen soll */
+	private boolean geomPrev = false;
+	/** Speichert, die FeatureCollection */
+	private FeatureCollection fullFeatureCollection = null;
+
+	/** Speichert den letzten Fehler in der Filter-Regel. */
+	protected Throwable testError = null;
+
+	/**
+	 * A Panel with a titled border that contains all buttons used to define the
+	 * filter
+	 */
+	protected JPanel defineFilterPanel;
+
+	/**
+	 * Erzeugt ein neues Panel.
+	 * 
+	 * @param fc
+	 *            definiert die zur Verfuegung gestellten Feature-Attribute
+	 * @param geomPrev
+	 *            bestimmt, ob ein Preview-Bereich angezeigt wird ({@code true})
+	 *            oder nicht ({@code false})
+	 * @see FeatureCollection#getSchema()
+	 */
+	public FeatureCollectionFilterPanel(FeatureCollection fc, boolean geomPrev) {
+		this(fc, geomPrev, true);
+	}
+
+	/**
+	 * Erzeugt ein neues Panel
+	 * 
+	 * @param fc
+	 *            definiert die zur Verfuegung gestellten Feature-Attribute
+	 * @param initGUI
+	 *            Flag, ob {@link #initGUI()} am Ende des Konstruktor aufgerufen
+	 *            werden soll (wenn {@code false} muss die explizit durch die
+	 *            Unterklasse erfolgen!)
+	 */
+	protected FeatureCollectionFilterPanel(FeatureCollection fc,
+			boolean geomPrev, boolean initGUI) {
+		super(fc.getSchema(), false);
+		this.geomPrev = geomPrev;
+
+		// Layout-Anordnung fuer GUI
+		layoutConstraints.get(ATTRIBUTE_TABLE).gridwidth = 3;
+		layoutConstraints.get(ATTRIBUTE_TABLE).weighty = 0.3;
+		layoutConstraints.get(RULE_TEXTFIELD).gridwidth = 2;
+		layoutConstraints.get(OPERATOR_COMBOBOX).gridx = 2;
+		layoutConstraints.put(TEST_BUTTON, new GridBagConstraints(0, 4, 1, 1,
+				0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE,
+				new Insets(5, 10, 10, 10), 0, 0));
+		layoutConstraints
+				.put(TESTRESULT_LABEL, new GridBagConstraints(1, 4, 2, 1, 1.0,
+						0.0, GridBagConstraints.WEST,
+						GridBagConstraints.HORIZONTAL,
+						new Insets(5, 10, 10, 10), 0, 0));
+		layoutConstraints.put(TESTRESULTDETAILS_BUTTON, new GridBagConstraints(
+				2, 4, 1, 1, 0, 0.0, GridBagConstraints.EAST,
+				GridBagConstraints.NONE, new Insets(5, 10, 10, 10), 0, 0));
+		layoutConstraints.put(PREVIEW_PANEL, new GridBagConstraints(0, 5, 3, 1,
+				0, 0.7, GridBagConstraints.CENTER, GridBagConstraints.BOTH,
+				new Insets(5, 10, 10, 10), 0, 0));
+
+		if (initGUI)
+			initGUI();
+
+		setFeatureCollection(fc);
+	}
+
+	/**
+	 * Initalisiert die GUI des Fensters. Der "Start-Button" der durch die
+	 * Oberklasse definiert wird, wird dabei aus dem Panel entfernt!
+	 */
+	protected void initGUI() {
+		super.initGUI();
+
+		// Button zum Testen des Filters
+		testButton = new JButton(GeotoolsGUIUtil.R(TEST_BUTTON));
+		testButton.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				performRuleTest();
+			}
+		});
+
+		// Button fuer Details des Test-Ergebnis
+		testResultDetails = new JButton(GeotoolsGUIUtil
+				.R(TESTRESULTDETAILS_BUTTON));
+		testResultDetails.setVisible(false);
+		testResultDetails.setToolTipText(GeotoolsGUIUtil
+				.R(TESTRESULTDETAILS_TOOLTIP));
+		testResultDetails.addActionListener(new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				ExceptionDialog.show(FeatureCollectionFilterPanel.this,
+						testError, true);
+			}
+		});
+
+		// Label fuer Fehler-Meldungen
+		testResult = new JLabel("");
+		// Schrift: rot und fett
+		testResult.setForeground(Color.RED);
+		testResult.setFont(testResult.getFont().deriveFont(Font.BOLD));
+
+		if (getPreviewPanel() == null) {
+
+			setPreviewPanel(new FeatureTablePane(null, geomPrev) {
+
+				// In der Tabelle sollen einzelne Werte selektiert werden
+				// koennen
+				// und diese bei einem Doppelklick in die Formel uebernommen
+				// werden
+				@Override
+				protected void initGUI(boolean geomPreview) {
+					super.initGUI(geomPreview);
+
+					mapPane
+							.setToolTipText(GeotoolsGUIUtil
+									.R(FeatureCollectionFilterPanel.PREVIEW_MAPPANE_TOOLTIP));
+
+					// nur einzelne Zellen duerfen selektiert werden
+					featuresTable.setColumnSelectionAllowed(true);
+					featuresTable
+							.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+					// beim Klick auf eine Tabellenzelle, soll der Wert in die
+					// Formel
+					// uebernommen werden
+					featuresTable.addMouseListener(new MouseAdapter() {
+						public void mouseClicked(MouseEvent e) {
+							if (e.getButton() == MouseEvent.BUTTON1
+									&& e.getClickCount() == 2)
+
+								// * TODO SK: Might have to be changed to Sorted
+								// / RowModel stuff ....?!
+								insertValueInRule(featuresTable.getValueAt(
+										featuresTable.getSelectedRow(),
+										featuresTable.getSelectedColumn()));
+						}
+					});
+
+					// /*
+					// * Der TableModelListener aus super.initGUI() will bei
+					// einem
+					// * tableChanged event nur die selektieren anzeigen. In der
+					// * vorschau eines filters läuft das anders.
+					// */
+					// final int length =
+					// featuresTableModel.getTableModelListeners().length;
+					// if (length > 0)
+					// featuresTableModel
+					// .removeTableModelListener(featuresTableModel
+					// .getTableModelListeners()[length - 1]);
+					//
+					// // Wenn neue FeatureCollection gesetzt wird, alle
+					// Features
+					// // in Vorschau anzeigen.
+					// featuresTableModel
+					// .addTableModelListener(new TableModelListener() {
+					// public void tableChanged(TableModelEvent e) {
+					// showFeaturesInMap(getFeatureCollection());
+					// }
+					// });
+				}
+
+				// Im Vorschau-Panel sollen nicht die in der Tabelle selektieren
+				// Features angezeigt werden, sondern immer ALLE Features der
+				// Tabelle (also das Resultat des Filters)
+				@Override
+				public void performListSelection() {
+				}
+
+				@Override
+				/*
+				 * This method differs from the super-method! This method does
+				 * not care about selections in the table. It shows the complete
+				 * table (= paramter fc) as a selection on top of the complete
+				 * feature collection (which is rendered in gray).
+				 */
+				protected void showFeaturesInMap() {
+
+					if (getPreviewPanel() == null)
+						return;
+
+					FeatureCollection specialFeatureCollection = getFeatureCollection();
+
+					final FeatureCollection allFeatures = FeatureCollectionFilterPanel.this
+							.getFeatureCollection();
+
+					if (specialFeatureCollection != null && allFeatures != null)
+						LOGGER.debug("The result to show contains "
+								+ specialFeatureCollection.size()
+								+ " of total " + allFeatures.size());
+
+					if (getPreviewPanel().mapPane.getContext().getLayerCount() == 0) {
+
+						if (allFeatures != null) {
+							/**
+							 * Als unterstes layer sollen alle Features in grau
+							 * dargestellt werden. Dieses Layer soll nur einmal
+							 * eingefügt werden
+							 */
+							getPreviewPanel().mapPane.getContext().addLayer(
+									new DefaultMapLayer(allFeatures,
+											StylingUtil.createStyleSimple(
+													allFeatures,
+													Color.lightGray,
+													Color.darkGray)));
+
+							// This thows an exception... We have to move to GT
+							// filters i guess.
+							getPreviewPanel().mapPane.zoomTo(allFeatures);
+						}
+					}
+
+					if (specialFeatureCollection != null && allFeatures != null) {
+						/**
+						 * Der Inhalt der Tabelle soll in rot darüber gezeichnet
+						 * werden. Dieses layer wird jedes mal neu erstellt.
+						 */
+						if (getPreviewPanel().mapPane.getContext()
+								.getLayerCount() > 1)
+							getPreviewPanel().mapPane.getContext().removeLayer(
+									1);
+
+						// nur neues Layer erzeugen, wenn FeatureCollection
+						// NICHT leer (sonst Exception im StreamingRenderer!)
+						if (specialFeatureCollection.size() > 0)
+							getPreviewPanel().mapPane.getContext().addLayer(
+									new DefaultMapLayer(
+											specialFeatureCollection,
+											StylingUtil.createStyleSimple(
+													specialFeatureCollection,
+													Color.red, Color.white)));
+					}
+				}
+			});
+
+			// The PreviewPanel gets a Border saying what it is
+			getPreviewPanel().setBorder(
+					BorderFactory.createTitledBorder(GeotoolsGUIUtil
+							.R(RESULTS_BORDER_TITLE)));
+
+			// SwingUtil.setPreferredWidth(getPreviewPanel(), 600);
+		}
+		// Geometry-Attribute sollen nicht angezeigt werden
+		getPreviewPanel().setAttributeFilter(AttributeTypeFilter.NO_GEOMETRY);
+
+		SwingUtil.setPreferredHeight(getPreviewPanel(), 150);
+
+		/**
+		 * Move all the Components that have been added so far into a new panel
+		 * that has a nice border.
+		 */
+		defineFilterPanel = new JPanel(getLayout());
+		// SwingUtil.setPreferredWidth(defineFilterPanel, 600);
+		defineFilterPanel.setBorder(BorderFactory
+				.createTitledBorder(GeotoolsGUIUtil
+						.R(FILER_DEFINITION_BORDER_TITLE)));
+		GridBagLayout gpl = (GridBagLayout) getLayout();
+		for (Component c : getComponents()) {
+			defineFilterPanel.add(c, gpl.getConstraints(c));
+		}
+		removeAll(); // From the contentpane
+		setLayout(new BorderLayout());
+
+		// zusaetzliche Komponenten einfuegen
+		defineFilterPanel.add(testButton, layoutConstraints.get(TEST_BUTTON));
+		defineFilterPanel.add(testResultDetails, layoutConstraints
+				.get(TESTRESULTDETAILS_BUTTON));
+		defineFilterPanel.add(testResult, layoutConstraints
+				.get(TESTRESULT_LABEL));
+
+		add(defineFilterPanel, BorderLayout.NORTH);
+
+		add(getPreviewPanel(), BorderLayout.CENTER);
+
+		// listen to the moment, the panel is inserted into a frame
+		// and then set the TEST-Button the default button
+		addAncestorListener(new AncestorListener() {
+			@Override
+			public void ancestorAdded(AncestorEvent event) {
+				if (getRootPane() != null
+						&& getRootPane().getDefaultButton() == null)
+					getRootPane().setDefaultButton(testButton);
+
+			}
+
+			@Override
+			public void ancestorMoved(AncestorEvent event) {
+			}
+
+			@Override
+			public void ancestorRemoved(AncestorEvent event) {
+			}
+		});
+	}
+
+	/**
+	 * Setzt den Filter, der die dargestellten Attribute bestimmt.
+	 * 
+	 * @param attrFilter
+	 *            Filter
+	 */
+	public void setAttributeFilter(AttributeTypeFilter attrFilter) {
+		super.setAttributeFilter(attrFilter);
+		// Filter auch auf die in der Vorschau dargestellten
+		// Attribut-Spalten anwenden
+		getPreviewPanel().setAttributeFilter(attrFilter);
+	}
+
+	/**
+	 * Setzt die Labels des Panels neu.
+	 * 
+	 * @param captionMap
+	 *            Map
+	 * @see FeatureFilterPanel#resetCaptions(Map)
+	 */
+	public void resetCaptions(Map<String, Object> captionMap) {
+		super.resetCaptions(captionMap);
+		SwingUtil.resetCaption(testButton, captionMap.get(TEST_BUTTON));
+
+		/**
+		 * TODO ?! resteCaption doesn't handle BorderTitle yet
+		 * SwingUtil.resetCaption(defineFilterPanel.getBorder(),
+		 * captionMap.get(FILER_DEFINITION_BORDER_TITLE)); //
+		 * defineFilterPanel.setBorder(
+		 * BorderFactory.createTitledBorder(GeotoolsGUIUtil.RESOURCE //
+		 * .getString(FILER_DEFINITION_BORDER_TITLE)));
+		 */
+	}
+
+	/**
+	 * Fuegt an der Curserposition einen Wert in die Formel ein.
+	 * 
+	 * @param value
+	 *            Object
+	 */
+	protected void insertValueInRule(Object value) {
+		if (value == null)
+			value = "";
+
+		String ruleValue = value.toString();
+		// Nur numerische Werte direkt in Formel einfuegen.
+		// Andere Werte als String in Anfuehrungsstrichen gekapselt.
+		if (!(value instanceof Number))
+			ruleValue = "\"" + ruleValue + "\"";
+		// Wert in Formel einfuegen
+		performOperatorInsert(ruleValue, (JTextField) this.rule
+				.getInputComponent());
+		// Fokus zurueck auf Formel-Feld
+		rule.grabFocus();
+	}
+
+	/**
+	 * Setzt die aktuell im Dialog eingegebene Formel und aktualisiert die
+	 * Vorschau.
+	 * 
+	 * @param rule
+	 *            Formel als String
+	 */
+	public void setRule(String rule) {
+		super.setRule(rule);
+		performRuleTest();
+	}
+
+	/**
+	 * Wird ausgefuehrt, wenn der Testen-Button gedrueckt wird. Erzeugt einen
+	 * Filter aus der angegebenen Formel, wertet diese auf der
+	 * {@link FeatureCollection} aus und zeigt das Resultat im
+	 * {@linkplain #previewPanel Vorschau-Bereich} an. <br>
+	 * Tritt ein Fehler auf, wird die entsprechende Meldung im Label
+	 * {@link #testResult} (neben dem Button) angezeigt.
+	 * 
+	 */
+	protected void performRuleTest() {
+		try {
+			FeatureCollection subCollection = filterFeatureCollection();
+			getPreviewPanel().setFeatureCollection(subCollection);
+			resetComponentsAfterTest(null);
+		} catch (Exception err) {
+			getPreviewPanel().setFeatureCollection(null);
+			resetComponentsAfterTest(err);
+		}
+		rule.grabFocus();
+	}
+
+	/**
+	 * (De)aktiviert Label und Button fuer die Fehlermeldung entsprechend einer
+	 * etwaigen Fehlermeldung. Wird ausgefuehrt nachdem der "Test"-Button
+	 * geklickt wurde.
+	 * 
+	 * @param err
+	 *            Fehler (kann {@code null} sein)
+	 */
+	protected void resetComponentsAfterTest(Throwable err) {
+		testError = err;
+		testResult.setText(err != null ? err.getMessage() : "");
+		testResultDetails.setVisible(err != null);
+	}
+
+	/**
+	 * Setzt die {@link FeatureCollection}, die (gefiltert) in der Vorschau
+	 * angezeigt wird.
+	 * 
+	 * @param fc
+	 *            eine {@link FeatureCollection}, die zum Feature-Type (Schema)
+	 *            des Formel-Panels passt
+	 * @exception IllegalArgumentException
+	 *                falls die FeatureCollection nicht zum Schema des Panels
+	 *                passt
+	 * @see FeatureCollection#getSchema()
+	 */
+	public void setFeatureCollection(FeatureCollection fc) {
+		if (getFeatureType() == null)
+			setFeatureType(fc.getSchema());
+		if (!fc.getSchema().equals(getFeatureType()))
+			throw new IllegalArgumentException(
+					"FeatureCollection does not fit to schema of the panel!");
+		this.fullFeatureCollection = fc;
+
+		if (getPreviewPanel() != null) {
+			getPreviewPanel().setFeatureCollection(fc);
+		}
+	}
+
+	/**
+	 * Liefert die ungefilterte {@link FeatureCollection}, auf der gefiltert
+	 * wird.
+	 */
+	public FeatureCollection getFeatureCollection() {
+		return fullFeatureCollection;
+	}
+
+	/**
+	 * Setzt den Style, in dem die Features in der Vorschau dargestellt werden.
+	 * 
+	 * @param style
+	 *            Style fuer die Features
+	 */
+	public void setFeatureStyle(Style style) {
+		getPreviewPanel().setFeatureStyle(style);
+	}
+
+	/**
+	 * Liefert den Style, in dem die Features in der Vorschau dargestellt
+	 * werden.
+	 */
+	public Style getFeatureStyle() {
+		return getPreviewPanel().getFeatureStyle();
+	}
+
+	/**
+	 * Wendet die im Panel eingetragene Filter-Formel auf die
+	 * {@link FeatureCollection} des Vorschau-Fensters an und liefert die
+	 * entsprechende Sub-Collection.
+	 * 
+	 * @see FeatureCollection#subCollection(Filter)
+	 */
+	public FeatureCollection filterFeatureCollection() {
+		return getFeatureCollection().subCollection(createFilter());
+	}
+
+	/**
+	 * Wendet die im Panel eingetragene Filter-Formel auf eine
+	 * {@link FeatureCollection} and und liefert die entsprechende
+	 * Sub-Collection.
+	 * 
+	 * @see FeatureCollection#subCollection(Filter)
+	 */
+	public FeatureCollection filterFeatureCollection(FeatureCollection fc) {
+		return fc.subCollection(createFilter());
+	}
+
+	/**
+	 * Öffentliche Methode um die Belegung der Vorschaukomponente zu ändern.
+	 * Sollte vor dem Aufruf von {@link #initGUI()} gesetzt werden, da diese
+	 * Methode {@link #getPreviewPanel()} benutzt.
+	 * 
+	 * @param previewPanel
+	 *            Das zu setzende {@link FeatureTablePane} oder eine eigene
+	 *            Erweiterung
+	 * @author SK
+	 */
+	public void setPreviewPanel(FeatureTablePane previewPanel) {
+		this.previewPanel = previewPanel;
+	}
+
+	/**
+	 * Liefert die aktuell gesetzt Vorschaukomponente. Kann auch
+	 * <code>null</code> zurückgeben. Wir in {@link #initGUI()} verwendet.
+	 */
+	public FeatureTablePane getPreviewPanel() {
+		return previewPanel;
+	}
+}

Modified: trunk/src/schmitzm/geotools/gui/FeatureCollectionFrame.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/FeatureCollectionFrame.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/FeatureCollectionFrame.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,100 +1,118 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.gui;
-
-import java.awt.BorderLayout;
-
-import javax.swing.JFrame;
-
-import org.geotools.feature.FeatureCollection;
-
-import schmitzm.swing.table.SelectionTableModel;
-
-/**
- * Dieses Fenster stellt eine {@link FeatureCollection} als Tabelle dar.
- * Optional wird links neben der Tabelle eine grafische Vorschau der in
- * der Tabelle selektierten Features angezeigt.
- * @see FeatureCollectionPane
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class FeatureCollectionFrame extends JFrame {
-  /** Enthaelt die Tabelle (und den Preview-Bereich). */
-  protected FeatureTablePane featuresPane = null;
-
-  /**
-   * Erzeugt ein neues Fenster inklusive Preview-Bereich fuer die in der
-   * Tabelle selektieren Features.
-   */
-  public FeatureCollectionFrame() {
-    this(null, true);
-  }
-
-  /**
-   * Erzeugt ein neues Fenster.
-   * @param geomPreview bestimmt, ob ein Preview-Bereich angezeigt wird ({@code true})
-   *                    oder nicht ({@code false})
-   */
-  public FeatureCollectionFrame(boolean geomPreview) {
-    this(null, geomPreview);
-  }
-
-  /**
-   * Erzeugt ein neues Fenster inklusive Preview-Bereich fuer die in der
-   * Tabelle selektieren Features.
-   * @param fc angezeigte Features
-   */
-  public FeatureCollectionFrame(FeatureCollection fc) {
-    this(fc, true);
-  }
-
-  /**
-   * Erzeugt ein neues Fenster.
-   * @param fc angezeigte Features
-   * @param geomPreview bestimmt, ob ein Preview-Bereich angezeigt wird ({@code true})
-   *                    oder nicht ({@code false})
-   */
-  public FeatureCollectionFrame(FeatureCollection fc, boolean geomPreview) {
-    super();
-    this.setLayout( new BorderLayout() );
-    this.setDefaultCloseOperation( JFrame.HIDE_ON_CLOSE );
-    this.featuresPane = new FeatureTablePane(fc,geomPreview) {
-      protected void initGUI(boolean geomPreview) {
-        super.initGUI(geomPreview);
-        // Reset the table model to show a selection column
-        featuresTable.setModel( new SelectionTableModel(featuresTableModel, featuresTable) );
-        // Because SortableJTable is used, the first col is always a checkbox.
-        // TODO: How wide is a CheckBox in differnet L'n'F s?
-        int selCol = featuresTable.convertColumnIndexToModel(0);
-        featuresTable.getColumnModel().getColumn(selCol).setMaxWidth(17);
-        featuresTable.getColumnModel().getColumn(selCol).setMinWidth(17);
-      }
-    };
-    this.getContentPane().add( featuresPane );
-    this.pack();
-  }
-
-  /**
-   * Setzt die anzuzeigende {@link FeatureCollection}.
-   * @param fc Features
-   */
-  public void setFeatureCollection(FeatureCollection fc) {
-    featuresPane.setFeatureCollection(fc);
-  }
-
-  /**
-   * Liefert die angezeigte {@link FeatureCollection}.
-   */
-  public FeatureTablePane getFeatureCollectionPane() {
-    return this.featuresPane;
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.gui;
+
+import java.awt.BorderLayout;
+
+import javax.swing.JFrame;
+
+import org.geotools.feature.FeatureCollection;
+
+import schmitzm.swing.table.SelectionTableModel;
+
+/**
+ * Dieses Fenster stellt eine {@link FeatureCollection} als Tabelle dar.
+ * Optional wird links neben der Tabelle eine grafische Vorschau der in
+ * der Tabelle selektierten Features angezeigt.
+ * @see FeatureCollectionPane
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class FeatureCollectionFrame extends JFrame {
+  /** Enthaelt die Tabelle (und den Preview-Bereich). */
+  protected FeatureTablePane featuresPane = null;
+
+  /**
+   * Erzeugt ein neues Fenster inklusive Preview-Bereich fuer die in der
+   * Tabelle selektieren Features.
+   */
+  public FeatureCollectionFrame() {
+    this(null, true);
+  }
+
+  /**
+   * Erzeugt ein neues Fenster.
+   * @param geomPreview bestimmt, ob ein Preview-Bereich angezeigt wird ({@code true})
+   *                    oder nicht ({@code false})
+   */
+  public FeatureCollectionFrame(boolean geomPreview) {
+    this(null, geomPreview);
+  }
+
+  /**
+   * Erzeugt ein neues Fenster inklusive Preview-Bereich fuer die in der
+   * Tabelle selektieren Features.
+   * @param fc angezeigte Features
+   */
+  public FeatureCollectionFrame(FeatureCollection fc) {
+    this(fc, true);
+  }
+
+  /**
+   * Erzeugt ein neues Fenster.
+   * @param fc angezeigte Features
+   * @param geomPreview bestimmt, ob ein Preview-Bereich angezeigt wird ({@code true})
+   *                    oder nicht ({@code false})
+   */
+  public FeatureCollectionFrame(FeatureCollection fc, boolean geomPreview) {
+    super();
+    this.setLayout( new BorderLayout() );
+    this.setDefaultCloseOperation( JFrame.HIDE_ON_CLOSE );
+    this.featuresPane = new FeatureTablePane(fc,geomPreview) {
+      protected void initGUI(boolean geomPreview) {
+        super.initGUI(geomPreview);
+        // Reset the table model to show a selection column
+        featuresTable.setModel( new SelectionTableModel(featuresTableModel, featuresTable) );
+        // Because SortableJTable is used, the first col is always a checkbox.
+        // TODO: How wide is a CheckBox in differnet L'n'F s?
+        int selCol = featuresTable.convertColumnIndexToModel(0);
+        featuresTable.getColumnModel().getColumn(selCol).setMaxWidth(17);
+        featuresTable.getColumnModel().getColumn(selCol).setMinWidth(17);
+      }
+    };
+    this.getContentPane().add( featuresPane );
+    this.pack();
+  }
+
+  /**
+   * Setzt die anzuzeigende {@link FeatureCollection}.
+   * @param fc Features
+   */
+  public void setFeatureCollection(FeatureCollection fc) {
+    featuresPane.setFeatureCollection(fc);
+  }
+
+  /**
+   * Liefert die angezeigte {@link FeatureCollection}.
+   */
+  public FeatureTablePane getFeatureCollectionPane() {
+    return this.featuresPane;
+  }
+}

Modified: trunk/src/schmitzm/geotools/gui/FeatureCollectionTableModel.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/FeatureCollectionTableModel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/FeatureCollectionTableModel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,279 +1,298 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.geotools.gui;
-
-import java.util.HashMap;
-import java.util.Vector;
-
-import javax.swing.table.AbstractTableModel;
-
-import org.geotools.feature.AttributeType;
-import org.geotools.feature.Feature;
-import org.geotools.feature.FeatureCollection;
-import org.geotools.feature.FeatureCollections;
-import org.geotools.feature.FeatureIterator;
-import org.geotools.feature.FeatureType;
-
-import schmitzm.geotools.feature.AttributeTypeFilter;
-import schmitzm.geotools.feature.FeatureUtil;
-
-/**
- * Tabellen-Modell fuer eine FeatureCollection. Aus Effizienzgruenden
- * (um wahlfreien Zugriff zu erreichen) werden die Features beim Aufruf von
- * {@link #setFeatureCollection(FeatureCollection)} in ein Array kopiert.
- * Veraenderungen an der zugrunde liegenden {@link FeatureCollection} werden
- * somit nicht automatisch in das Tabellen-Modell uebernommen, sondern es ist
- * ein expliziter Aufruf von {@link #reorganize()} notwendig.<br>
- * Bis zu diesem Punkt arbeitet diese Tabellen-Modell identisch zum
- * {@code FeatureTableModel} von Geotools. Im Gegensatz zu
- * {@link org.geotools.gui.swing.table.FeatureTableModel org.geotools.gui.swing.table.FeatureTableModel}.
- * werden die Tabellennamen und die Anzahl an Spalten jedoch nicht bei jedem Zugriff
- * neu aus dem ersten Feature ermittelt, sondern global gespeichert. Dies ist
- * erffizienter, da das haeufige Oeffnen eines {@link FeatureIterator FeatureIterators}
- * vermieden wird.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class FeatureCollectionTableModel extends AbstractTableModel {
-  /** Holds the feature table that will be represented by this model. */
-  protected FeatureCollection featureTable = null;
-  /** Array mit den Daten von {@link #featureTable}. Wird nur beim Aufruf von
-   *  {@link #reorganize} befuellt. */
-  protected Feature[] featureArray;
-  /** Spaltennamen. Wird nur beim Aufruf von {@link #reorganize} befuellt. */
-  protected String[] colNames = null;
-  /** Spalten-Typen. Wird nur beim Aufruf von {@link #reorganize} befuellt. */
-  protected Class<?>[] colClass = null;
-  /** Bestimmt die angezeigten Features */
-  protected AttributeTypeFilter attrFilter = AttributeTypeFilter.ALL;
-
-  /** Speichert die angezeigten Attribut-Typen. */
-  protected Vector<AttributeType> attrTypes = new Vector<AttributeType>();
-  /** Speichert den Attribut-Index fuer jede Spalte (wichtig, wenn nicht
-   *  alle Spalten angezeigt werden!) */
-  protected int[] attrIdxForCol = null;
-  /** Speichert die Indexe der Features im TableModel um die Funktion
-   *  {@link #findFeature(Feature)} moeglichst effizient zugestalten. 
-   *  Der Key ist nicht das Feature, sondern die FeatureID, weil 
-   *  {@link Feature} die equals methode nicht überschreibt.*/
-  protected HashMap<String,Integer> featureIdx = null;
-
-  /**
-   * Erzeugt ein neues (leeres) Tabellen-Modell.
-   */
-  public FeatureCollectionTableModel() {
-    this(null);
-  }
-
-  /**
-   * Erzeugt ein neues Tabellen-Modell.
-   * @param features Daten fuer die Tabelle
-   */
-  public FeatureCollectionTableModel(final FeatureCollection features) {
-    super();
-    setFeatureCollection(features);
-  }
-
-  /**
-   * Baut die interne Datenbasis (Array) des Tabellen-Modells neu auf.
-   * Muss aufgerufen werden, damit nachtraegliche Aenderungen an der
-   * zugrunde liegenden {@link FeatureCollection} in das Tabellenmodell
-   * uebernommen werden.
-   */
-  public void reorganize() {
-    reorganize(true);
-  }
-  
-  /**
-   * Baut die interne Datenbasis (Array) des Tabellen-Modells neu auf.
-   * Muss aufgerufen werden, damit nachtraegliche Aenderungen an der
-   * zugrunde liegenden {@link FeatureCollection} in das Tabellenmodell
-   * uebernommen werden.
-   * @param fireTableStructureChanged bestimmt, ob nach dem Neu-Aufbau
-   *        ein entsprechendes Event initiiert wird
-   */
-  protected void reorganize(boolean fireTableStructureChanged) {
-    featureArray = FeatureUtil.featuresToArray(featureTable);
-    if ( featureArray == null || featureArray.length == 0 ) {
-      colNames = new String[0];
-      colClass = new Class[0];
-    } else {
-      // Struktur der Tabelle von erstem Feature uebernehmen
-      FeatureType ft = featureArray[0].getFeatureType();
-      // Pruefen, welche Attribute angezeigt werden
-      attrTypes.clear();
-      for (int i=0; i<ft.getAttributeCount(); i++) {
-        AttributeType type = ft.getAttributeType(i);
-        if ( attrFilter == null || attrFilter.accept( type, i ) )
-          attrTypes.add( type );
-      }
-      // Namen und Attribut-Indizes der angezeigten Spalten ermitteln
-      colNames      = new String[ attrTypes.size() ];
-      colClass      = new Class[ attrTypes.size() ];
-      attrIdxForCol = new int[ attrTypes.size() ];
-      for (int i=0; i<colNames.length; i++) {
-        int idx = ft.find( attrTypes.elementAt(i) );
-        attrIdxForCol[i] = idx;
-        colNames[i]      = ft.getAttributeType(idx).getLocalName();
-        colClass[i]      = ft.getAttributeType(idx).getBinding();
-      }
-    }
-
-    // store feature indexes in HashMap to optimize findFeature(.)
-    featureIdx = new HashMap<String, Integer>();
-    for (int i=0; i<featureArray.length; i++)
-      if ( featureArray[i] != null )
-        featureIdx.put(featureArray[i].getID(), i);
-    
-    if ( fireTableStructureChanged )
-      fireTableStructureChanged();
-  }
-
-  /**
-   * Setzt die FeatureCollection fuer das Tabellen-Modell.
-   * Ruft {@link #reorganize} auf.<br>
-   * Nachtraegliche Aenderungen an der {@link FeatureCollection} werden
-   * erst nach erneutem {@link #reorganize()} in das Tabellen-Modell uebernommen!
-   * @param features Daten-Basis fuer die Tabelle
-   */
-  public void setFeatureCollection(final FeatureCollection features) {
-      featureTable = features;
-      reorganize();
-   }
-
-  /**
-   * Liefert die FeatureCollection fuer das Tabellen-Modell.
-   * Nachtraegliche Aenderungen an der {@link FeatureCollection} werden
-   * erst nach erneutem {@link #reorganize()} in das Tabellen-Modell uebernommen!
-   */
-  public FeatureCollection getFeatureCollection() {
-    return featureTable;
-  }
-
-  /**
-   * Liefert den Filter, der die dargestellten Attribut-Spalten bestimmt.
-   */
-  public AttributeTypeFilter getAttributeFilter() {
-    return attrFilter;
-  }
-
-  /**
-   * Setzt den Filter, der die dargestellten Attribut-Spalten bestimmt.
-   * @param attrFilter Filter
-   */
-  public void setAttributeFilter(AttributeTypeFilter attrFilter) {
-    this.attrFilter = attrFilter;
-    // Filter neu anwenden
-    reorganize();
-  }
-
-  /**
-   * Liefert die Anzahl an Spalten der Tabelle. Entspricht der Anzahl an
-   * Attributen der Features.
-   */
-  public int getColumnCount() {
-    return colNames == null ? 0 : colNames.length;
-  }
-
-  /**
-   * Liefert einen Spaltennamen der Tabelle. Entspricht den Attributnamen
-   * des (ersten) Features der Collection.
-   * @param col Spalten-Index, beginnend bei 0
-   */
-  public String getColumnName(int col) {
-    return colNames == null || col >= colNames.length ? "" : colNames[col];
-  }
-
-  /**
-   * Liefert die Anzahl an Zeilen der Tabelle. Entspricht der Anzahl an
-   * Features in der Collection.
-   */
-  public int getRowCount() {
-    if (featureArray == null)
-      featureArray = FeatureUtil.featuresToArray(featureTable);
-    return featureArray.length;
-  }
-
-  /**
-   * Liefert eine Zellen-Wert.
-   * @param row Zeilennummer (Feature), beginnend bei 0
-   * @param col Spaltennummer (Attribut), beginnen bei 0
-   */
-  public Object getValueAt(final int row, final int col) {
-      if (featureArray == null)
-          featureArray = FeatureUtil.featuresToArray(featureTable);
-      if (featureArray[row] == null)
-        return null;
-      return featureArray[row].getAttribute( attrIdxForCol[col] );
-  }
-  
-  /**
-   * Liefert die Klasse des Feature-Attributs.
-   * @param col Spaltennummer (Attribut), beginnen bei 0
-   */
-  @Override
-  public Class<?> getColumnClass(int col) {
-    return colClass[col];
-  }
-
-  /**
-   * Liefert Features der Tabelle als Array.
-   * @param idx Indizes der FeatureCollection
-   */
-  public Feature[] getFeaturesAsArray(int[] idx) {
-    Feature[] features = new Feature[ idx == null ? 0 : idx.length ];
-    for (int i=0; i<features.length; i++)
-      features[i] = featureArray[ idx[i] ];
-    return features;
-  }
-
-  /**
-   * Liefert Features der Tabelle als Collection.
-   * @param idx Indizes der FeatureCollection
-   */
-  public FeatureCollection getFeaturesAsCollection(int[] idx) {
-    FeatureCollection featureCol = FeatureCollections.newCollection();
-    for (int i=0; idx != null && i<idx.length; i++)
-      featureCol.add( featureArray[ idx[i] ] );
-    return featureCol;
-  }
-
-  /**
-   * Returns a Feature of the model.
-   * @param row row index
-   */
-  public Feature getFeature(int row) {
-   return featureArray[row]; 
-  }
-  
-  /**
-   * Returns the index of a {@link Feature} in the model.
-   * @param f a feature
-   * @return -1 if the model does not contain the feature
-   */
-  public int findFeature(Feature f) {
-   return findFeature(f.getID());
-  }
-  
-  /**
-   * Returns the index of a {@link Feature} in the model.
-   * @param fid A feature-ID
-   * @return -1 if the model does not contain the feature
-   */
-  public int findFeature(String fId) {
-   Integer idx = featureIdx.get(fId);
-   if ( idx != null )
-     return idx;
-   return -1; 
-  }
-  
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.gui;
+
+import java.util.HashMap;
+import java.util.Vector;
+
+import javax.swing.table.AbstractTableModel;
+
+import org.geotools.feature.AttributeType;
+import org.geotools.feature.Feature;
+import org.geotools.feature.FeatureCollection;
+import org.geotools.feature.FeatureCollections;
+import org.geotools.feature.FeatureIterator;
+import org.geotools.feature.FeatureType;
+
+import schmitzm.geotools.feature.AttributeTypeFilter;
+import schmitzm.geotools.feature.FeatureUtil;
+
+/**
+ * Tabellen-Modell fuer eine FeatureCollection. Aus Effizienzgruenden
+ * (um wahlfreien Zugriff zu erreichen) werden die Features beim Aufruf von
+ * {@link #setFeatureCollection(FeatureCollection)} in ein Array kopiert.
+ * Veraenderungen an der zugrunde liegenden {@link FeatureCollection} werden
+ * somit nicht automatisch in das Tabellen-Modell uebernommen, sondern es ist
+ * ein expliziter Aufruf von {@link #reorganize()} notwendig.<br>
+ * Bis zu diesem Punkt arbeitet diese Tabellen-Modell identisch zum
+ * {@code FeatureTableModel} von Geotools. Im Gegensatz zu
+ * {@link org.geotools.gui.swing.table.FeatureTableModel org.geotools.gui.swing.table.FeatureTableModel}.
+ * werden die Tabellennamen und die Anzahl an Spalten jedoch nicht bei jedem Zugriff
+ * neu aus dem ersten Feature ermittelt, sondern global gespeichert. Dies ist
+ * erffizienter, da das haeufige Oeffnen eines {@link FeatureIterator FeatureIterators}
+ * vermieden wird.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class FeatureCollectionTableModel extends AbstractTableModel {
+  /** Holds the feature table that will be represented by this model. */
+  protected FeatureCollection featureTable = null;
+  /** Array mit den Daten von {@link #featureTable}. Wird nur beim Aufruf von
+   *  {@link #reorganize} befuellt. */
+  protected Feature[] featureArray;
+  /** Spaltennamen. Wird nur beim Aufruf von {@link #reorganize} befuellt. */
+  protected String[] colNames = null;
+  /** Spalten-Typen. Wird nur beim Aufruf von {@link #reorganize} befuellt. */
+  protected Class<?>[] colClass = null;
+  /** Bestimmt die angezeigten Features */
+  protected AttributeTypeFilter attrFilter = AttributeTypeFilter.ALL;
+
+  /** Speichert die angezeigten Attribut-Typen. */
+  protected Vector<AttributeType> attrTypes = new Vector<AttributeType>();
+  /** Speichert den Attribut-Index fuer jede Spalte (wichtig, wenn nicht
+   *  alle Spalten angezeigt werden!) */
+  protected int[] attrIdxForCol = null;
+  /** Speichert die Indexe der Features im TableModel um die Funktion
+   *  {@link #findFeature(Feature)} moeglichst effizient zugestalten. 
+   *  Der Key ist nicht das Feature, sondern die FeatureID, weil 
+   *  {@link Feature} die equals methode nicht überschreibt.*/
+  protected HashMap<String,Integer> featureIdx = null;
+
+  /**
+   * Erzeugt ein neues (leeres) Tabellen-Modell.
+   */
+  public FeatureCollectionTableModel() {
+    this(null);
+  }
+
+  /**
+   * Erzeugt ein neues Tabellen-Modell.
+   * @param features Daten fuer die Tabelle
+   */
+  public FeatureCollectionTableModel(final FeatureCollection features) {
+    super();
+    setFeatureCollection(features);
+  }
+
+  /**
+   * Baut die interne Datenbasis (Array) des Tabellen-Modells neu auf.
+   * Muss aufgerufen werden, damit nachtraegliche Aenderungen an der
+   * zugrunde liegenden {@link FeatureCollection} in das Tabellenmodell
+   * uebernommen werden.
+   */
+  public void reorganize() {
+    reorganize(true);
+  }
+  
+  /**
+   * Baut die interne Datenbasis (Array) des Tabellen-Modells neu auf.
+   * Muss aufgerufen werden, damit nachtraegliche Aenderungen an der
+   * zugrunde liegenden {@link FeatureCollection} in das Tabellenmodell
+   * uebernommen werden.
+   * @param fireTableStructureChanged bestimmt, ob nach dem Neu-Aufbau
+   *        ein entsprechendes Event initiiert wird
+   */
+  protected void reorganize(boolean fireTableStructureChanged) {
+    featureArray = FeatureUtil.featuresToArray(featureTable);
+    if ( featureArray == null || featureArray.length == 0 ) {
+      colNames = new String[0];
+      colClass = new Class[0];
+    } else {
+      // Struktur der Tabelle von erstem Feature uebernehmen
+      FeatureType ft = featureArray[0].getFeatureType();
+      // Pruefen, welche Attribute angezeigt werden
+      attrTypes.clear();
+      for (int i=0; i<ft.getAttributeCount(); i++) {
+        AttributeType type = ft.getAttributeType(i);
+        if ( attrFilter == null || attrFilter.accept( type, i ) )
+          attrTypes.add( type );
+      }
+      // Namen und Attribut-Indizes der angezeigten Spalten ermitteln
+      colNames      = new String[ attrTypes.size() ];
+      colClass      = new Class[ attrTypes.size() ];
+      attrIdxForCol = new int[ attrTypes.size() ];
+      for (int i=0; i<colNames.length; i++) {
+        int idx = ft.find( attrTypes.elementAt(i) );
+        attrIdxForCol[i] = idx;
+        colNames[i]      = ft.getAttributeType(idx).getLocalName();
+        colClass[i]      = ft.getAttributeType(idx).getBinding();
+      }
+    }
+
+    // store feature indexes in HashMap to optimize findFeature(.)
+    featureIdx = new HashMap<String, Integer>();
+    for (int i=0; i<featureArray.length; i++)
+      if ( featureArray[i] != null )
+        featureIdx.put(featureArray[i].getID(), i);
+    
+    if ( fireTableStructureChanged )
+      fireTableStructureChanged();
+  }
+
+  /**
+   * Setzt die FeatureCollection fuer das Tabellen-Modell.
+   * Ruft {@link #reorganize} auf.<br>
+   * Nachtraegliche Aenderungen an der {@link FeatureCollection} werden
+   * erst nach erneutem {@link #reorganize()} in das Tabellen-Modell uebernommen!
+   * @param features Daten-Basis fuer die Tabelle
+   */
+  public void setFeatureCollection(final FeatureCollection features) {
+      featureTable = features;
+      reorganize();
+   }
+
+  /**
+   * Liefert die FeatureCollection fuer das Tabellen-Modell.
+   * Nachtraegliche Aenderungen an der {@link FeatureCollection} werden
+   * erst nach erneutem {@link #reorganize()} in das Tabellen-Modell uebernommen!
+   */
+  public FeatureCollection getFeatureCollection() {
+    return featureTable;
+  }
+
+  /**
+   * Liefert den Filter, der die dargestellten Attribut-Spalten bestimmt.
+   */
+  public AttributeTypeFilter getAttributeFilter() {
+    return attrFilter;
+  }
+
+  /**
+   * Setzt den Filter, der die dargestellten Attribut-Spalten bestimmt.
+   * @param attrFilter Filter
+   */
+  public void setAttributeFilter(AttributeTypeFilter attrFilter) {
+    this.attrFilter = attrFilter;
+    // Filter neu anwenden
+    reorganize();
+  }
+
+  /**
+   * Liefert die Anzahl an Spalten der Tabelle. Entspricht der Anzahl an
+   * Attributen der Features.
+   */
+  public int getColumnCount() {
+    return colNames == null ? 0 : colNames.length;
+  }
+
+  /**
+   * Liefert einen Spaltennamen der Tabelle. Entspricht den Attributnamen
+   * des (ersten) Features der Collection.
+   * @param col Spalten-Index, beginnend bei 0
+   */
+  public String getColumnName(int col) {
+    return colNames == null || col >= colNames.length ? "" : colNames[col];
+  }
+
+  /**
+   * Liefert die Anzahl an Zeilen der Tabelle. Entspricht der Anzahl an
+   * Features in der Collection.
+   */
+  public int getRowCount() {
+    if (featureArray == null)
+      featureArray = FeatureUtil.featuresToArray(featureTable);
+    return featureArray.length;
+  }
+
+  /**
+   * Liefert eine Zellen-Wert.
+   * @param row Zeilennummer (Feature), beginnend bei 0
+   * @param col Spaltennummer (Attribut), beginnen bei 0
+   */
+  public Object getValueAt(final int row, final int col) {
+      if (featureArray == null)
+          featureArray = FeatureUtil.featuresToArray(featureTable);
+      if (featureArray[row] == null)
+        return null;
+      return featureArray[row].getAttribute( attrIdxForCol[col] );
+  }
+  
+  /**
+   * Liefert die Klasse des Feature-Attributs.
+   * @param col Spaltennummer (Attribut), beginnen bei 0
+   */
+  @Override
+  public Class<?> getColumnClass(int col) {
+    return colClass[col];
+  }
+
+  /**
+   * Liefert Features der Tabelle als Array.
+   * @param idx Indizes der FeatureCollection
+   */
+  public Feature[] getFeaturesAsArray(int[] idx) {
+    Feature[] features = new Feature[ idx == null ? 0 : idx.length ];
+    for (int i=0; i<features.length; i++)
+      features[i] = featureArray[ idx[i] ];
+    return features;
+  }
+
+  /**
+   * Liefert Features der Tabelle als Collection.
+   * @param idx Indizes der FeatureCollection
+   */
+  public FeatureCollection getFeaturesAsCollection(int[] idx) {
+    FeatureCollection featureCol = FeatureCollections.newCollection();
+    for (int i=0; idx != null && i<idx.length; i++)
+      featureCol.add( featureArray[ idx[i] ] );
+    return featureCol;
+  }
+
+  /**
+   * Returns a Feature of the model.
+   * @param row row index
+   */
+  public Feature getFeature(int row) {
+   return featureArray[row]; 
+  }
+  
+  /**
+   * Returns the index of a {@link Feature} in the model.
+   * @param f a feature
+   * @return -1 if the model does not contain the feature
+   */
+  public int findFeature(Feature f) {
+   return findFeature(f.getID());
+  }
+  
+  /**
+   * Returns the index of a {@link Feature} in the model.
+   * @param fid A feature-ID
+   * @return -1 if the model does not contain the feature
+   */
+  public int findFeature(String fId) {
+   Integer idx = featureIdx.get(fId);
+   if ( idx != null )
+     return idx;
+   return -1; 
+  }
+  
+
+}

Modified: trunk/src/schmitzm/geotools/gui/FeatureFilterPanel.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/FeatureFilterPanel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/FeatureFilterPanel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,255 +1,284 @@
-package schmitzm.geotools.gui;
-
-import java.awt.GridBagConstraints;
-import java.awt.Insets;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-import java.util.Map;
-
-import javax.swing.JLabel;
-import javax.swing.JScrollPane;
-import javax.swing.JTable;
-import javax.swing.JTextField;
-import javax.swing.ListSelectionModel;
-
-import org.geotools.feature.FeatureCollection;
-import org.geotools.feature.FeatureType;
-import org.geotools.filter.Filter;
-
-import schmitzm.geotools.feature.AttributeTypeFilter;
-import schmitzm.geotools.feature.FeatureOperationTree;
-import schmitzm.geotools.feature.FeatureOperationTreeFilter;
-import schmitzm.geotools.feature.FeatureOperationTreeParser;
-import schmitzm.geotools.feature.FeatureTypeTableModel;
-import schmitzm.swing.OperationTreePanel;
-import schmitzm.swing.SwingUtil;
-
-/**
- * Diese Klasse stellt ein Panel zur Vefuegung, mit der ein
- * {@link FeatureOperationTreeFilter} in Form einer arithmetischen (und
- * boolschen) Formel erstellt werden kann.
- * 
- * @see FeatureOperationTree
- * @see FeatureOperationTreeParser
- * @see FeatureOperationTreeFilter
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- *         (University of Bonn/Germany)
- * @version 1.0
- */
-public class FeatureFilterPanel extends OperationTreePanel {
-	/**
-	 * Konstante fuer das Label zur Tabelle der Feature-Attribute.
-	 * 
-	 * @see #layoutConstraints
-	 * @see #resetCaptions(Map)
-	 */
-	public static final String ATTRIBUTE_LABEL = FeatureFilterPanel.class
-			.getName()
-			+ ".FeatureAttributeLabel";
-	/**
-	 * Konstante fuer die Tabelle der Feature-Attribute.
-	 * 
-	 * @see #layoutConstraints
-	 */
-	public static final String ATTRIBUTE_TABLE = FeatureFilterPanel.class
-			.getName()
-			+ ".FeatureAttributeTable";
-
-	/** Label ueber der Tabelle mit den Feature-Attributen. */
-	protected JLabel attributeLabel = null;
-	/** Tabelle in der die Feature-Attribute angegeben werden. */
-	protected JTable attributeTable = null;
-	/** Tabellen-Modell, das den Inhalt der Feature-Attribut-Tabelle bestimmt */
-	protected FeatureTypeTableModel attributeTableModel = null;
-	private JScrollPane attributeScrollPane = null;
-
-	/**
-	 * Erzeugt ein neues Panel.
-	 * 
-	 * @param ftype
-	 *            definiert die zur Verfuegung gestellten Feature-Attribute
-	 * @see FeatureCollection#getSchema()
-	 */
-	public FeatureFilterPanel(FeatureType ftype) {
-		this(ftype, true);
-	}
-
-	/**
-	 * Erzeugt ein neues Panel.
-	 * 
-	 * @param fc
-	 *            definiert die zur Verfuegung gestellten Feature-Attribute
-	 * @see FeatureCollection#getSchema()
-	 */
-	public FeatureFilterPanel(FeatureCollection fc) {
-		this(fc.getSchema());
-	}
-
-	/**
-	 * Erzeugt ein neues Panel
-	 * 
-	 * @param ftype
-	 *            definiert die zur Verfuegung gestellten Feature-Attribute
-	 * @param initGUI
-	 *            Flag, ob {@link #initGUI()} am Ende des Konstruktor aufgerufen
-	 *            werden soll (wenn {@code false} muss die explizit durch die
-	 *            Unterklasse erfolgen!)
-	 */
-	protected FeatureFilterPanel(FeatureType ftype, boolean initGUI) {
-		super(false);
-
-		// Zusaetzliche Operatoren und Konstanten
-		// avOperators.add(...); avOperatorsDesc.put(..., ...);
-
-		// Layout-Anordnung fuer GUI
-		layoutConstraints.put(ATTRIBUTE_LABEL, new GridBagConstraints(0, 0, 2,
-				1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE,
-				new Insets(5, 10, 0, 10), 0, 0));
-		layoutConstraints.put(ATTRIBUTE_TABLE, new GridBagConstraints(0, 1, 2,
-				1, 1.0, 1.0, GridBagConstraints.CENTER,
-				GridBagConstraints.BOTH, new Insets(0, 10, 5, 10), 0, 0));
-		layoutConstraints.put(RULE_TEXTFIELD, new GridBagConstraints(0, 2, 1,
-				1, 1.0, 0, GridBagConstraints.WEST,
-				GridBagConstraints.HORIZONTAL, new Insets(0, 10, 5, 10), 0, 0));
-		layoutConstraints.put(OPERATOR_COMBOBOX, new GridBagConstraints(1, 2,
-				1, 1, 0.0, 0, GridBagConstraints.SOUTHEAST,
-				GridBagConstraints.HORIZONTAL, new Insets(0, 10, 5, 10), 2, 2));
-		layoutConstraints.put(START_BUTTON, new GridBagConstraints(0, 3, 1, 1,
-				0.0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE,
-				new Insets(0, 10, 5, 10), 0, 0));
-
-		if (initGUI) {
-			initGUI();
-			setFeatureType(ftype);
-		}
-	}
-
-	/**
-	 * Initalisiert die GUI des Fensters. Der "Start-Button" der durch die
-	 * Oberklasse definiert wird, wird dabei aus dem Panel entfernt!
-	 */
-	protected void initGUI() {
-		super.initGUI();
-
-		attributeTableModel = new FeatureTypeTableModel();
-		attributeTableModel.setAttributeFilter(AttributeTypeFilter.NO_GEOMETRY);
-		attributeTable = new JTable(attributeTableModel);
-		// SK.Begin 09-03-05
-		// No Change, just the comment, that you can re-add the Header with
-		// attributeTable.setTableHeader( new JTableHeader(
-		// attributeTable.getColumnModel() ) );
-		// SK.Ende 09-03-05
-		attributeTable.setTableHeader(null);
-		
-		attributeTable.setShowGrid(false);
-		attributeTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
-		attributeScrollPane = new JScrollPane(attributeTable);
-		SwingUtil.setPreferredHeight(attributeScrollPane, 50);
-
-		// Bei Doppelklick auf Tabelle wird der Attribut-Name in die Formel
-		// eingefuegt
-		attributeTable.addMouseListener(new MouseAdapter() {
-			public void mouseClicked(MouseEvent e) {
-				// Nur auf Doppelklick reagieren
-				if (e.getButton() != MouseEvent.BUTTON1
-						|| e.getClickCount() != 2)
-					return;
-				// Selektiertes Attribut ermitteln
-				String attrName = (String) attributeTableModel.getValueAt(
-						attributeTable.getSelectedRow(), 0);
-				// Attribut-Namen in Formel einfuegen
-				performOperatorInsert("$" + attrName, (JTextField) rule
-						.getInputComponent());
-				// Fokus zurueck auf Formel-Feld
-				rule.grabFocus();
-			}
-		});
-
-		// kein "startButton"
-		remove(this.startButton);
-		// zusaetzliche Komponenten einfuegen
-		this.attributeLabel = new JLabel(GeotoolsGUIUtil.RESOURCE
-				.getString("Attributes")
-				+ ":");
-		add(attributeLabel, layoutConstraints.get(ATTRIBUTE_LABEL));
-		add(attributeScrollPane, layoutConstraints.get(ATTRIBUTE_TABLE));
-	}
-
-	/**
-	 * Setzt die Labels des Panels neu.
-	 * 
-	 * @param captionMap
-	 *            Map
-	 * @see OperationTreePanel#resetCaptions(Map)
-	 */
-	public void resetCaptions(Map<String, Object> captionMap) {
-		super.resetCaptions(captionMap);
-		SwingUtil.resetCaption(attributeLabel, captionMap.get(ATTRIBUTE_LABEL));
-	}
-
-	/**
-	 * Setzt den {@link FeatureType}, dessen Attribute fuer die Filter-Formel
-	 * angeboten werden.
-	 * 
-	 * @param ftype
-	 *            ein {@link FeatureType}
-	 */
-	public void setFeatureType(FeatureType ftype) {
-		attributeTableModel.setFeatureType(ftype);
-	}
-
-	/**
-	 * Liefert den {@link FeatureType}, dessen Attribute fuer die Filter-Formel
-	 * angeboten werden.
-	 */
-	public FeatureType getFeatureType() {
-		return attributeTableModel.getFeatureType();
-	}
-
-	/**
-	 * Liefert den Filter, der die dargestellten Attribute bestimmt.
-	 */
-	public AttributeTypeFilter getAttributeFilter() {
-		return attributeTableModel.getAttributeFilter();
-	}
-
-	/**
-	 * Setzt den Filter, der die dargestellten Attribute bestimmt.
-	 * 
-	 * @param attrFilter
-	 *            Filter
-	 * @see FeatureTypeTableModel#setAttributeFilter(AttributeTypeFilter)
-	 */
-	public void setAttributeFilter(AttributeTypeFilter attrFilter) {
-		attributeTableModel.setAttributeFilter(attrFilter);
-	}
-
-	/**
-	 * Liefert die im Panel eingetragene Formel.
-	 */
-	public String getRule() {
-		return rule.getValue();
-	}
-
-	/**
-	 * Setzt die im Panel eingegebene Formel.
-	 * 
-	 * @param ruleString
-	 *            Formel als String
-	 */
-	public void setRule(String ruleString) {
-		rule.setValue(ruleString);
-	}
-
-	/**
-	 * Liefert einen {@link Filter} zu der im Panel eingetragene Formel.
-	 * 
-	 * @return TRUE-Regel, falls im Panel keine Formel eingetragen ist.
-	 */
-	public Filter createFilter() {
-		String rule = getRule();
-		if (rule == null || rule.trim().equals(""))
-			rule = "1";
-		return new FeatureOperationTreeFilter(rule);
-	}
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.gui;
+
+import java.awt.GridBagConstraints;
+import java.awt.Insets;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.Map;
+
+import javax.swing.JLabel;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+import javax.swing.JTextField;
+import javax.swing.ListSelectionModel;
+
+import org.geotools.feature.FeatureCollection;
+import org.geotools.feature.FeatureType;
+import org.geotools.filter.Filter;
+
+import schmitzm.geotools.feature.AttributeTypeFilter;
+import schmitzm.geotools.feature.FeatureOperationTree;
+import schmitzm.geotools.feature.FeatureOperationTreeFilter;
+import schmitzm.geotools.feature.FeatureOperationTreeParser;
+import schmitzm.geotools.feature.FeatureTypeTableModel;
+import schmitzm.swing.OperationTreePanel;
+import schmitzm.swing.SwingUtil;
+
+/**
+ * Diese Klasse stellt ein Panel zur Vefuegung, mit der ein
+ * {@link FeatureOperationTreeFilter} in Form einer arithmetischen (und
+ * boolschen) Formel erstellt werden kann.
+ * 
+ * @see FeatureOperationTree
+ * @see FeatureOperationTreeParser
+ * @see FeatureOperationTreeFilter
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *         (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class FeatureFilterPanel extends OperationTreePanel {
+	/**
+	 * Konstante fuer das Label zur Tabelle der Feature-Attribute.
+	 * 
+	 * @see #layoutConstraints
+	 * @see #resetCaptions(Map)
+	 */
+	public static final String ATTRIBUTE_LABEL = FeatureFilterPanel.class
+			.getName()
+			+ ".FeatureAttributeLabel";
+	/**
+	 * Konstante fuer die Tabelle der Feature-Attribute.
+	 * 
+	 * @see #layoutConstraints
+	 */
+	public static final String ATTRIBUTE_TABLE = FeatureFilterPanel.class
+			.getName()
+			+ ".FeatureAttributeTable";
+
+	/** Label ueber der Tabelle mit den Feature-Attributen. */
+	protected JLabel attributeLabel = null;
+	/** Tabelle in der die Feature-Attribute angegeben werden. */
+	protected JTable attributeTable = null;
+	/** Tabellen-Modell, das den Inhalt der Feature-Attribut-Tabelle bestimmt */
+	protected FeatureTypeTableModel attributeTableModel = null;
+	private JScrollPane attributeScrollPane = null;
+
+	/**
+	 * Erzeugt ein neues Panel.
+	 * 
+	 * @param ftype
+	 *            definiert die zur Verfuegung gestellten Feature-Attribute
+	 * @see FeatureCollection#getSchema()
+	 */
+	public FeatureFilterPanel(FeatureType ftype) {
+		this(ftype, true);
+	}
+
+	/**
+	 * Erzeugt ein neues Panel.
+	 * 
+	 * @param fc
+	 *            definiert die zur Verfuegung gestellten Feature-Attribute
+	 * @see FeatureCollection#getSchema()
+	 */
+	public FeatureFilterPanel(FeatureCollection fc) {
+		this(fc.getSchema());
+	}
+
+	/**
+	 * Erzeugt ein neues Panel
+	 * 
+	 * @param ftype
+	 *            definiert die zur Verfuegung gestellten Feature-Attribute
+	 * @param initGUI
+	 *            Flag, ob {@link #initGUI()} am Ende des Konstruktor aufgerufen
+	 *            werden soll (wenn {@code false} muss die explizit durch die
+	 *            Unterklasse erfolgen!)
+	 */
+	protected FeatureFilterPanel(FeatureType ftype, boolean initGUI) {
+		super(false);
+
+		// Zusaetzliche Operatoren und Konstanten
+		// avOperators.add(...); avOperatorsDesc.put(..., ...);
+
+		// Layout-Anordnung fuer GUI
+		layoutConstraints.put(ATTRIBUTE_LABEL, new GridBagConstraints(0, 0, 2,
+				1, 0, 0, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE,
+				new Insets(5, 10, 0, 10), 0, 0));
+		layoutConstraints.put(ATTRIBUTE_TABLE, new GridBagConstraints(0, 1, 2,
+				1, 1.0, 1.0, GridBagConstraints.CENTER,
+				GridBagConstraints.BOTH, new Insets(0, 10, 5, 10), 0, 0));
+		layoutConstraints.put(RULE_TEXTFIELD, new GridBagConstraints(0, 2, 1,
+				1, 1.0, 0, GridBagConstraints.WEST,
+				GridBagConstraints.HORIZONTAL, new Insets(0, 10, 5, 10), 0, 0));
+		layoutConstraints.put(OPERATOR_COMBOBOX, new GridBagConstraints(1, 2,
+				1, 1, 0.0, 0, GridBagConstraints.SOUTHEAST,
+				GridBagConstraints.HORIZONTAL, new Insets(0, 10, 5, 10), 2, 2));
+		layoutConstraints.put(START_BUTTON, new GridBagConstraints(0, 3, 1, 1,
+				0.0, 0, GridBagConstraints.WEST, GridBagConstraints.NONE,
+				new Insets(0, 10, 5, 10), 0, 0));
+
+		if (initGUI) {
+			initGUI();
+			setFeatureType(ftype);
+		}
+	}
+
+	/**
+	 * Initalisiert die GUI des Fensters. Der "Start-Button" der durch die
+	 * Oberklasse definiert wird, wird dabei aus dem Panel entfernt!
+	 */
+	protected void initGUI() {
+		super.initGUI();
+
+		attributeTableModel = new FeatureTypeTableModel();
+		attributeTableModel.setAttributeFilter(AttributeTypeFilter.NO_GEOMETRY);
+		attributeTable = new JTable(attributeTableModel);
+		// SK.Begin 09-03-05
+		// No Change, just the comment, that you can re-add the Header with
+		// attributeTable.setTableHeader( new JTableHeader(
+		// attributeTable.getColumnModel() ) );
+		// SK.Ende 09-03-05
+		attributeTable.setTableHeader(null);
+		
+		attributeTable.setShowGrid(false);
+		attributeTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+		attributeScrollPane = new JScrollPane(attributeTable);
+		SwingUtil.setPreferredHeight(attributeScrollPane, 50);
+
+		// Bei Doppelklick auf Tabelle wird der Attribut-Name in die Formel
+		// eingefuegt
+		attributeTable.addMouseListener(new MouseAdapter() {
+			public void mouseClicked(MouseEvent e) {
+				// Nur auf Doppelklick reagieren
+				if (e.getButton() != MouseEvent.BUTTON1
+						|| e.getClickCount() != 2)
+					return;
+				// Selektiertes Attribut ermitteln
+				String attrName = (String) attributeTableModel.getValueAt(
+						attributeTable.getSelectedRow(), 0);
+				// Attribut-Namen in Formel einfuegen
+				performOperatorInsert("$" + attrName, (JTextField) rule
+						.getInputComponent());
+				// Fokus zurueck auf Formel-Feld
+				rule.grabFocus();
+			}
+		});
+
+		// kein "startButton"
+		remove(this.startButton);
+		// zusaetzliche Komponenten einfuegen
+		this.attributeLabel = new JLabel(GeotoolsGUIUtil.RESOURCE
+				.getString("Attributes")
+				+ ":");
+		add(attributeLabel, layoutConstraints.get(ATTRIBUTE_LABEL));
+		add(attributeScrollPane, layoutConstraints.get(ATTRIBUTE_TABLE));
+	}
+
+	/**
+	 * Setzt die Labels des Panels neu.
+	 * 
+	 * @param captionMap
+	 *            Map
+	 * @see OperationTreePanel#resetCaptions(Map)
+	 */
+	public void resetCaptions(Map<String, Object> captionMap) {
+		super.resetCaptions(captionMap);
+		SwingUtil.resetCaption(attributeLabel, captionMap.get(ATTRIBUTE_LABEL));
+	}
+
+	/**
+	 * Setzt den {@link FeatureType}, dessen Attribute fuer die Filter-Formel
+	 * angeboten werden.
+	 * 
+	 * @param ftype
+	 *            ein {@link FeatureType}
+	 */
+	public void setFeatureType(FeatureType ftype) {
+		attributeTableModel.setFeatureType(ftype);
+	}
+
+	/**
+	 * Liefert den {@link FeatureType}, dessen Attribute fuer die Filter-Formel
+	 * angeboten werden.
+	 */
+	public FeatureType getFeatureType() {
+		return attributeTableModel.getFeatureType();
+	}
+
+	/**
+	 * Liefert den Filter, der die dargestellten Attribute bestimmt.
+	 */
+	public AttributeTypeFilter getAttributeFilter() {
+		return attributeTableModel.getAttributeFilter();
+	}
+
+	/**
+	 * Setzt den Filter, der die dargestellten Attribute bestimmt.
+	 * 
+	 * @param attrFilter
+	 *            Filter
+	 * @see FeatureTypeTableModel#setAttributeFilter(AttributeTypeFilter)
+	 */
+	public void setAttributeFilter(AttributeTypeFilter attrFilter) {
+		attributeTableModel.setAttributeFilter(attrFilter);
+	}
+
+	/**
+	 * Liefert die im Panel eingetragene Formel.
+	 */
+	public String getRule() {
+		return rule.getValue();
+	}
+
+	/**
+	 * Setzt die im Panel eingegebene Formel.
+	 * 
+	 * @param ruleString
+	 *            Formel als String
+	 */
+	public void setRule(String ruleString) {
+		rule.setValue(ruleString);
+	}
+
+	/**
+	 * Liefert einen {@link Filter} zu der im Panel eingetragene Formel.
+	 * 
+	 * @return TRUE-Regel, falls im Panel keine Formel eingetragen ist.
+	 */
+	public Filter createFilter() {
+		String rule = getRule();
+		if (rule == null || rule.trim().equals(""))
+			rule = "1";
+		return new FeatureOperationTreeFilter(rule);
+	}
+}

Modified: trunk/src/schmitzm/geotools/gui/FeatureInputOption.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/FeatureInputOption.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/FeatureInputOption.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,107 +1,126 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.geotools.gui;
-
-import javax.swing.JScrollPane;
-import javax.swing.JTable;
-
-import org.geotools.feature.Feature;
-import org.geotools.feature.FeatureType;
-
-import schmitzm.geotools.feature.FeatureTableModel;
-import schmitzm.swing.InputOption;
-import schmitzm.swing.MultipleOptionPane;
-import schmitzm.swing.SwingUtil;
-
-/**
- * {@linkplain InputOption Eingabe-Option} zur Definition eines {@link Feature} im
- * {@link MultipleOptionPane}.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- */
-public class FeatureInputOption extends InputOption<Feature> {
-  /** Beinhaltet die Tabelle, in der die Attribute eingegeben
-   *  werden. */
-  protected JTable inpTable;
-  /** Beinhaltet das Tabellen-Modell, in dem die Attribute verwaltet
-   *  werden. */
-  protected FeatureTableModel inpTableModel;
-
-  /**
-   * Erzeugt einen neue Eingabe-Option.
-   * @param label Ueberschrift
-   * @param inputNeeded bestimmt, ob eine Eingabe erforderlich ist
-   * @param feature initalial dargestelltes {@link Feature}
-   */
-  public FeatureInputOption(String label, boolean inputNeeded, Feature feature) {
-    this(label, inputNeeded, feature != null ? feature.getFeatureType() : null);
-    setValue(feature);
-  }
-
-  /**
-   * Erzeugt einen neue Eingabe-Option.
-   * @param label Ueberschrift
-   * @param inputNeeded bestimmt, ob eine Eingabe erforderlich ist
-   * @param fType bestimmt die dargestellten Attribute (kann {@code null} sein)
-   */
-  public FeatureInputOption(String label, boolean inputNeeded, FeatureType fType) {
-    super(label, inputNeeded, true);
-    inpTableModel.setFeature(fType);
-  }
-
-  /**
-   * Erzeugt eine neue Instanz der Eingabe-Komponente. z.B. ein Text-Eingabefeld
-   * oder eine Combo-Box.
-   */
-  protected JScrollPane createInputComponent() {
-    this.inpTableModel = new FeatureTableModel();
-    this.inpTable      = new JTable( inpTableModel );
-    this.inpTable.setColumnSelectionAllowed(false);
-    this.inpTable.setRowSelectionAllowed(false);
-    SwingUtil.setPreferredHeight(this,200);
-    SwingUtil.setPreferredWidth(this,200);
-    return new JScrollPane(inpTable);
-  }
-
-  /**
-   * Liefert das aktuell in der Tabelle definierte {@link Feature}.
-   */
-  protected Feature performGetValue() {
-    // Workaround: Editieren der zuletzt editierten Zelle
-    //             beenden, damit Wert in Feature uebernommen
-    //             wird
-    inpTable.editCellAt(-1, -1);
-    return inpTableModel.getFeature();
-  }
-  /**
-   * Initalisiert die Tabelle mit einem neuen {@link Feature}.
-   * @param newValue neues {@link Feature}
-   * @return immer {@code true}
-   */
-  protected boolean performSetValue(Feature newValue) {
-    inpTableModel.setFeature(newValue);
-    return true;
-  }
-
-  /**
-   * Prueft, ob ein Feature definiert ist.
-   */
-  protected boolean performIsInputEmpty() {
-    return inpTableModel.getFeature() == null;
-  }
-
-  /**
-   * Prueft, ob die aktuelle Eingabe leer ist. Liefert immer {@code true}.
-   */
-  protected boolean performIsInputValid() {
-    return true;
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.gui;
+
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+
+import org.geotools.feature.Feature;
+import org.geotools.feature.FeatureType;
+
+import schmitzm.geotools.feature.FeatureTableModel;
+import schmitzm.swing.InputOption;
+import schmitzm.swing.MultipleOptionPane;
+import schmitzm.swing.SwingUtil;
+
+/**
+ * {@linkplain InputOption Eingabe-Option} zur Definition eines {@link Feature} im
+ * {@link MultipleOptionPane}.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ */
+public class FeatureInputOption extends InputOption<Feature> {
+  /** Beinhaltet die Tabelle, in der die Attribute eingegeben
+   *  werden. */
+  protected JTable inpTable;
+  /** Beinhaltet das Tabellen-Modell, in dem die Attribute verwaltet
+   *  werden. */
+  protected FeatureTableModel inpTableModel;
+
+  /**
+   * Erzeugt einen neue Eingabe-Option.
+   * @param label Ueberschrift
+   * @param inputNeeded bestimmt, ob eine Eingabe erforderlich ist
+   * @param feature initalial dargestelltes {@link Feature}
+   */
+  public FeatureInputOption(String label, boolean inputNeeded, Feature feature) {
+    this(label, inputNeeded, feature != null ? feature.getFeatureType() : null);
+    setValue(feature);
+  }
+
+  /**
+   * Erzeugt einen neue Eingabe-Option.
+   * @param label Ueberschrift
+   * @param inputNeeded bestimmt, ob eine Eingabe erforderlich ist
+   * @param fType bestimmt die dargestellten Attribute (kann {@code null} sein)
+   */
+  public FeatureInputOption(String label, boolean inputNeeded, FeatureType fType) {
+    super(label, inputNeeded, true);
+    inpTableModel.setFeature(fType);
+  }
+
+  /**
+   * Erzeugt eine neue Instanz der Eingabe-Komponente. z.B. ein Text-Eingabefeld
+   * oder eine Combo-Box.
+   */
+  protected JScrollPane createInputComponent() {
+    this.inpTableModel = new FeatureTableModel();
+    this.inpTable      = new JTable( inpTableModel );
+    this.inpTable.setColumnSelectionAllowed(false);
+    this.inpTable.setRowSelectionAllowed(false);
+    SwingUtil.setPreferredHeight(this,200);
+    SwingUtil.setPreferredWidth(this,200);
+    return new JScrollPane(inpTable);
+  }
+
+  /**
+   * Liefert das aktuell in der Tabelle definierte {@link Feature}.
+   */
+  protected Feature performGetValue() {
+    // Workaround: Editieren der zuletzt editierten Zelle
+    //             beenden, damit Wert in Feature uebernommen
+    //             wird
+    inpTable.editCellAt(-1, -1);
+    return inpTableModel.getFeature();
+  }
+  /**
+   * Initalisiert die Tabelle mit einem neuen {@link Feature}.
+   * @param newValue neues {@link Feature}
+   * @return immer {@code true}
+   */
+  protected boolean performSetValue(Feature newValue) {
+    inpTableModel.setFeature(newValue);
+    return true;
+  }
+
+  /**
+   * Prueft, ob ein Feature definiert ist.
+   */
+  protected boolean performIsInputEmpty() {
+    return inpTableModel.getFeature() == null;
+  }
+
+  /**
+   * Prueft, ob die aktuelle Eingabe leer ist. Liefert immer {@code true}.
+   */
+  protected boolean performIsInputValid() {
+    return true;
+  }
+
+}

Modified: trunk/src/schmitzm/geotools/gui/FeatureLayerFilterDialog.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/FeatureLayerFilterDialog.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/FeatureLayerFilterDialog.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,250 +1,279 @@
-package schmitzm.geotools.gui;
-
-import java.awt.BorderLayout;
-import java.awt.FlowLayout;
-import java.awt.Frame;
-import java.awt.Window;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.io.IOException;
-import java.util.Map;
-
-import javax.swing.JButton;
-import javax.swing.JDialog;
-import javax.swing.JPanel;
-
-import org.geotools.feature.FeatureCollection;
-import org.geotools.filter.Filter;
-import org.geotools.map.MapLayer;
-import org.geotools.map.event.MapLayerEvent;
-
-import schmitzm.geotools.map.event.FeatureSelectedEvent;
-import schmitzm.geotools.map.event.MapLayerAdapter;
-import schmitzm.swing.CaptionsChangeable;
-import schmitzm.swing.ExceptionDialog;
-import schmitzm.swing.SwingUtil;
-
-
-/**
- * Diese Klasse stellt einen Dialog dar, in dem eine {@link FeatureCollection}
- * ueber eine Formel gefiltert werden kann. Beim Anwenden des Filters wird
- * ein {@link FeatureSelectedEvent} ausgeloest, auf das z.B. mit dem
- * Einfuegen eines neuen Layers reagiert werden kann.
- * @see FeatureCollectionFilterPanel
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class FeatureLayerFilterDialog extends JDialog implements CaptionsChangeable {
-  /** Key, um den Titel des FeatureCollection-Filter-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String DIALOG_TITLE = FeatureLayerFilterDialog.class.getName()+".TITLE";
-  /** Key, um den OK-Button des FeatureCollection-Filter-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String OK_BUTTON = FeatureLayerFilterDialog.class.getName()+".OK";
-  /** Key, um den ABBRECHEN-Button des FeatureCollection-Filter-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String CANCEL_BUTTON = FeatureLayerFilterDialog.class.getName()+".CANCEL";
-  /** Key, um den ÃœBERNEHMEN-Button des FeatureCollection-Filter-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String APPLY_BUTTON = FeatureLayerFilterDialog.class.getName()+".APPLY";
-
-  /** Panel in dem der Filter definiert und getestet werden kann. */
-  protected FeatureCollectionFilterPanel filterPanel = null;
-  /** Der OK-Button. */
-  protected JButton okButton = null;
-  /** Der ABBRECHEN-Button. */
-  protected JButton cancelButton = null;
-  /** Der ANWENDEN-Button. */
-  protected JButton applyButton = null;
-
-  private String   frameTitle = GeotoolsGUIUtil.RESOURCE.getString(DIALOG_TITLE);
-  private JMapPane mapPane = null;
-  private MapLayer layer = null;
-
-  /**
-   * Erzeugt einen neuen Dialog.
-   * @param parent Uebergeordnetes Fenster (kann {@code null} sein)
-   * @param mapPane MapPane fuer welches {@link FeatureSelectedEvent} ausgeloest
-   *                werden
-   * @param mapLayer MapLayer, aus dem die FeatureCollection stammt, auf der der
-   *                 Filter definiert wird
-   * @exception IOException falls beim Ermitteln der {@link FeatureCollection} aus
-   *            dem Layer ein Fehler auftritt
-   *           
-   * CHANGE BY SK: Takes {@link Window} instead of {@link Frame}
-   * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
-   */
-  public FeatureLayerFilterDialog(Window parent, JMapPane mapPane, MapLayer mapLayer) throws IOException {
-    this(parent, mapPane, mapLayer, true);
-  }
-
-
-  /**
-   * Erzeugt einen neuen Dialog.
-   * @param parent Uebergeordnetes Fenster (kann {@code null} sein)
-   * @param mapPane MapPane fuer welches {@link FeatureSelectedEvent} ausgeloest
-   *                werden
-   * @param mapLayer MapLayer, aus dem die FeatureCollection stammt, auf der der
-   *                 Filter definiert wird
-   * @param initGUI bestimmt, ob {@link #initGUI()} aufgerufen werden soll. Wenn
-   *                {@code false}, muss der Konstruktor der Unterklasse dafuer
-   *                sorgen, dass {@link #initGUI()} aufgerufen wird
-   * @exception IOException falls beim Ermitteln der {@link FeatureCollection} aus
-   *            dem Layer ein Fehler auftritt
-   *            
-   * CHANGE BY SK: Takes {@link Window} instead of {@link Frame}     
-   * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>       
-   */
-  protected FeatureLayerFilterDialog(Window parent, JMapPane mapPane, MapLayer mapLayer, boolean initGUI) throws IOException {
-    super(parent);
-    setModal(true);
-    this.setTitle( frameTitle + " ["+mapLayer.getTitle()+"]" );
-    this.setLayout( new BorderLayout() );
-    this.setSize(380,200);
-    this.mapPane = mapPane;
-    this.layer   = mapLayer;
-    if ( initGUI ) {
-      initGUI();
-      pack();
-    }
-  }
-
-
-
-  /**
-   * Initalisiert die GUI.
-   */
-  protected void initGUI() throws IOException {
-    filterPanel = new FeatureCollectionFilterPanel( layer.getFeatureSource().getFeatures(), true ) {
-      @Override
-      protected void resetComponentsAfterTest(Throwable err) {
-        super.resetComponentsAfterTest(err);
-        // OK- und Uebernehmen-Button (de)aktivieren
-        okButton.setEnabled( err == null );
-        applyButton.setEnabled( err == null );
-      }
-      @Override
-      protected boolean acceptOperator(String operator) {
-        // Operatoren durch Methode des Dialogs filtern
-        return super.acceptOperator(operator) &&
-               FeatureLayerFilterDialog.this.acceptOperator(operator);
-      }
-    };
-    okButton = new JButton( SwingUtil.RESOURCE.getString("Ok") );
-    cancelButton = new JButton( SwingUtil.RESOURCE.getString("Cancel") );
-    applyButton = new JButton( SwingUtil.RESOURCE.getString("Apply") );
-    add( filterPanel, BorderLayout.CENTER);
-    JPanel buttonPanel = new JPanel( new FlowLayout(FlowLayout.CENTER, 10, 5) );
-    buttonPanel.add( okButton);
-    buttonPanel.add( cancelButton);
-    buttonPanel.add( applyButton);
-    add( buttonPanel, BorderLayout.SOUTH );
-
-    // Aktionen der Filter-Fenster-Button
-    ActionListener action = new ActionListener() {
-      public void actionPerformed(ActionEvent e) {
-        // Ok- und Apply-Button > Filter anwenden und Event erzeugen
-        if ( e.getSource() == okButton || e.getSource() == applyButton ) {
-          // FeatureCollection filtern
-          try {
-            FeatureCollection fc = filterPanel.filterFeatureCollection();
-            FeatureSelectedEvent fse = new FeatureSelectedEvent(getMapPane() , layer, fc.getBounds(), fc, FeatureLayerFilterDialog.this);
-            getMapPane().fireMapPaneEvent( fse );
-          } catch ( Exception err ) {
-            ExceptionDialog.show(filterPanel,err);
-            // Fenster nicht schliessen, bei OK!!
-            return;
-          }
-        }
-        // Ok- und Cancel-Button > Dialog schliessen
-        if ( e.getSource() == okButton || e.getSource() == cancelButton ) {
-          setVisible( false );
-        }
-      }
-    };
-    okButton.addActionListener( action );
-    cancelButton.addActionListener( action );
-    applyButton.addActionListener( action );
-
-    // Wenn sich die die Bezeichnung des Layers aendert, soll auch der
-    // Titel des Filter-Fensters geaendert werden
-    layer.addMapLayerListener( new MapLayerAdapter() {
-      public void layerChanged(MapLayerEvent e) {
-        // Bezeichnung der Checkbox aendern
-        setTitle(frameTitle + " ["+layer.getTitle()+"]");
-      }
-    });
-  }
-
-  /**
-   * Kann von Sub-Klassen ueberschrieben werden, um bestimmte Operatoren
-   * in der Auswahl-Liste auszublenden.
-   * @param operator ein Operator
-   * @return immer {@code true}
-   */
-  protected boolean acceptOperator(String operator) {
-    return true;
-  }
-
-  /**
-   * Liefert das MapPane, fuer das {@link FeatureSelectedEvent FeatureSelectedEvents}
-   * ausgeloest werden.
-   */
-  public JMapPane getMapPane() {
-    return mapPane;
-  }
-
-  /**
-   * Liefert das Layer, aus dem die {@link FeatureCollection} stammt auf der
-   * der Filter definiert wird.
-   */
-  public MapLayer getMapLayer() {
-    return layer;
-  }
-
-  /**
-   * Liefert das Panel, in dem der Filter definiert und die Vorschau angezeigt
-   * wird.
-   */
-  public FeatureCollectionFilterPanel getFeatureCollectionFilterPanel() {
-    return filterPanel;
-  }
-
-  /**
-   * Liefert die aktuell im Dialog eingegebene Formel.
-   */
-  public String getFilterRule() {
-    return filterPanel.getRule();
-  }
-
-  /**
-   * Setzt die im Dialog eingegebene Formel und aktualisiert entsprechend die
-   * Vorschau
-   * @param rule Formel als String
-   */
-  public void setFilterRule(String rule) {
-    filterPanel.setRule(rule);
-  }
-
-  /**
-   * Liefert den Filter der aktuell im Dialog eingegebenen Formel.
-   */
-  public Filter getFilter() {
-    return filterPanel.createFilter();
-  }
-
-  /**
-   * Belegt die Labels und Buttons im Dialog neu
-   * @param captionMap Map in der die neuen Labels hinterlegt sind.
-   * @see FeatureLayerFilterDialog
-   */
-  public void resetCaptions(Map<String,Object> captionMap) {
-    SwingUtil.resetCaption ( okButton, captionMap.get(OK_BUTTON) );
-    SwingUtil.resetCaption ( applyButton, captionMap.get(APPLY_BUTTON) );
-    SwingUtil.resetCaption ( cancelButton, captionMap.get(CANCEL_BUTTON) );
-    Object caption = captionMap.get( DIALOG_TITLE );
-    if ( caption != null ) {
-      frameTitle = caption.toString();
-      // Damit Layer-Bezeichnung in Titel uebernommen wird, ein MapLayerEvent
-      // ausloesen
-      layer.setTitle( layer.getTitle() );
-    }
-    filterPanel.resetCaptions( captionMap );
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.gui;
+
+import java.awt.BorderLayout;
+import java.awt.FlowLayout;
+import java.awt.Frame;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.IOException;
+import java.util.Map;
+
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JPanel;
+
+import org.geotools.feature.FeatureCollection;
+import org.geotools.filter.Filter;
+import org.geotools.map.MapLayer;
+import org.geotools.map.event.MapLayerEvent;
+
+import schmitzm.geotools.map.event.FeatureSelectedEvent;
+import schmitzm.geotools.map.event.MapLayerAdapter;
+import schmitzm.swing.CaptionsChangeable;
+import schmitzm.swing.ExceptionDialog;
+import schmitzm.swing.SwingUtil;
+
+
+/**
+ * Diese Klasse stellt einen Dialog dar, in dem eine {@link FeatureCollection}
+ * ueber eine Formel gefiltert werden kann. Beim Anwenden des Filters wird
+ * ein {@link FeatureSelectedEvent} ausgeloest, auf das z.B. mit dem
+ * Einfuegen eines neuen Layers reagiert werden kann.
+ * @see FeatureCollectionFilterPanel
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class FeatureLayerFilterDialog extends JDialog implements CaptionsChangeable {
+  /** Key, um den Titel des FeatureCollection-Filter-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String DIALOG_TITLE = FeatureLayerFilterDialog.class.getName()+".TITLE";
+  /** Key, um den OK-Button des FeatureCollection-Filter-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String OK_BUTTON = FeatureLayerFilterDialog.class.getName()+".OK";
+  /** Key, um den ABBRECHEN-Button des FeatureCollection-Filter-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String CANCEL_BUTTON = FeatureLayerFilterDialog.class.getName()+".CANCEL";
+  /** Key, um den ÃœBERNEHMEN-Button des FeatureCollection-Filter-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String APPLY_BUTTON = FeatureLayerFilterDialog.class.getName()+".APPLY";
+
+  /** Panel in dem der Filter definiert und getestet werden kann. */
+  protected FeatureCollectionFilterPanel filterPanel = null;
+  /** Der OK-Button. */
+  protected JButton okButton = null;
+  /** Der ABBRECHEN-Button. */
+  protected JButton cancelButton = null;
+  /** Der ANWENDEN-Button. */
+  protected JButton applyButton = null;
+
+  private String   frameTitle = GeotoolsGUIUtil.RESOURCE.getString(DIALOG_TITLE);
+  private JMapPane mapPane = null;
+  private MapLayer layer = null;
+
+  /**
+   * Erzeugt einen neuen Dialog.
+   * @param parent Uebergeordnetes Fenster (kann {@code null} sein)
+   * @param mapPane MapPane fuer welches {@link FeatureSelectedEvent} ausgeloest
+   *                werden
+   * @param mapLayer MapLayer, aus dem die FeatureCollection stammt, auf der der
+   *                 Filter definiert wird
+   * @exception IOException falls beim Ermitteln der {@link FeatureCollection} aus
+   *            dem Layer ein Fehler auftritt
+   *           
+   * CHANGE BY SK: Takes {@link Window} instead of {@link Frame}
+   * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
+   */
+  public FeatureLayerFilterDialog(Window parent, JMapPane mapPane, MapLayer mapLayer) throws IOException {
+    this(parent, mapPane, mapLayer, true);
+  }
+
+
+  /**
+   * Erzeugt einen neuen Dialog.
+   * @param parent Uebergeordnetes Fenster (kann {@code null} sein)
+   * @param mapPane MapPane fuer welches {@link FeatureSelectedEvent} ausgeloest
+   *                werden
+   * @param mapLayer MapLayer, aus dem die FeatureCollection stammt, auf der der
+   *                 Filter definiert wird
+   * @param initGUI bestimmt, ob {@link #initGUI()} aufgerufen werden soll. Wenn
+   *                {@code false}, muss der Konstruktor der Unterklasse dafuer
+   *                sorgen, dass {@link #initGUI()} aufgerufen wird
+   * @exception IOException falls beim Ermitteln der {@link FeatureCollection} aus
+   *            dem Layer ein Fehler auftritt
+   *            
+   * CHANGE BY SK: Takes {@link Window} instead of {@link Frame}     
+   * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>       
+   */
+  protected FeatureLayerFilterDialog(Window parent, JMapPane mapPane, MapLayer mapLayer, boolean initGUI) throws IOException {
+    super(parent);
+    setModal(true);
+    this.setTitle( frameTitle + " ["+mapLayer.getTitle()+"]" );
+    this.setLayout( new BorderLayout() );
+    this.setSize(380,200);
+    this.mapPane = mapPane;
+    this.layer   = mapLayer;
+    if ( initGUI ) {
+      initGUI();
+      pack();
+    }
+  }
+
+
+
+  /**
+   * Initalisiert die GUI.
+   */
+  protected void initGUI() throws IOException {
+    filterPanel = new FeatureCollectionFilterPanel( layer.getFeatureSource().getFeatures(), true ) {
+      @Override
+      protected void resetComponentsAfterTest(Throwable err) {
+        super.resetComponentsAfterTest(err);
+        // OK- und Uebernehmen-Button (de)aktivieren
+        okButton.setEnabled( err == null );
+        applyButton.setEnabled( err == null );
+      }
+      @Override
+      protected boolean acceptOperator(String operator) {
+        // Operatoren durch Methode des Dialogs filtern
+        return super.acceptOperator(operator) &&
+               FeatureLayerFilterDialog.this.acceptOperator(operator);
+      }
+    };
+    okButton = new JButton( SwingUtil.RESOURCE.getString("Ok") );
+    cancelButton = new JButton( SwingUtil.RESOURCE.getString("Cancel") );
+    applyButton = new JButton( SwingUtil.RESOURCE.getString("Apply") );
+    add( filterPanel, BorderLayout.CENTER);
+    JPanel buttonPanel = new JPanel( new FlowLayout(FlowLayout.CENTER, 10, 5) );
+    buttonPanel.add( okButton);
+    buttonPanel.add( cancelButton);
+    buttonPanel.add( applyButton);
+    add( buttonPanel, BorderLayout.SOUTH );
+
+    // Aktionen der Filter-Fenster-Button
+    ActionListener action = new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        // Ok- und Apply-Button > Filter anwenden und Event erzeugen
+        if ( e.getSource() == okButton || e.getSource() == applyButton ) {
+          // FeatureCollection filtern
+          try {
+            FeatureCollection fc = filterPanel.filterFeatureCollection();
+            FeatureSelectedEvent fse = new FeatureSelectedEvent(getMapPane() , layer, fc.getBounds(), fc, FeatureLayerFilterDialog.this);
+            getMapPane().fireMapPaneEvent( fse );
+          } catch ( Exception err ) {
+            ExceptionDialog.show(filterPanel,err);
+            // Fenster nicht schliessen, bei OK!!
+            return;
+          }
+        }
+        // Ok- und Cancel-Button > Dialog schliessen
+        if ( e.getSource() == okButton || e.getSource() == cancelButton ) {
+          setVisible( false );
+        }
+      }
+    };
+    okButton.addActionListener( action );
+    cancelButton.addActionListener( action );
+    applyButton.addActionListener( action );
+
+    // Wenn sich die die Bezeichnung des Layers aendert, soll auch der
+    // Titel des Filter-Fensters geaendert werden
+    layer.addMapLayerListener( new MapLayerAdapter() {
+      public void layerChanged(MapLayerEvent e) {
+        // Bezeichnung der Checkbox aendern
+        setTitle(frameTitle + " ["+layer.getTitle()+"]");
+      }
+    });
+  }
+
+  /**
+   * Kann von Sub-Klassen ueberschrieben werden, um bestimmte Operatoren
+   * in der Auswahl-Liste auszublenden.
+   * @param operator ein Operator
+   * @return immer {@code true}
+   */
+  protected boolean acceptOperator(String operator) {
+    return true;
+  }
+
+  /**
+   * Liefert das MapPane, fuer das {@link FeatureSelectedEvent FeatureSelectedEvents}
+   * ausgeloest werden.
+   */
+  public JMapPane getMapPane() {
+    return mapPane;
+  }
+
+  /**
+   * Liefert das Layer, aus dem die {@link FeatureCollection} stammt auf der
+   * der Filter definiert wird.
+   */
+  public MapLayer getMapLayer() {
+    return layer;
+  }
+
+  /**
+   * Liefert das Panel, in dem der Filter definiert und die Vorschau angezeigt
+   * wird.
+   */
+  public FeatureCollectionFilterPanel getFeatureCollectionFilterPanel() {
+    return filterPanel;
+  }
+
+  /**
+   * Liefert die aktuell im Dialog eingegebene Formel.
+   */
+  public String getFilterRule() {
+    return filterPanel.getRule();
+  }
+
+  /**
+   * Setzt die im Dialog eingegebene Formel und aktualisiert entsprechend die
+   * Vorschau
+   * @param rule Formel als String
+   */
+  public void setFilterRule(String rule) {
+    filterPanel.setRule(rule);
+  }
+
+  /**
+   * Liefert den Filter der aktuell im Dialog eingegebenen Formel.
+   */
+  public Filter getFilter() {
+    return filterPanel.createFilter();
+  }
+
+  /**
+   * Belegt die Labels und Buttons im Dialog neu
+   * @param captionMap Map in der die neuen Labels hinterlegt sind.
+   * @see FeatureLayerFilterDialog
+   */
+  public void resetCaptions(Map<String,Object> captionMap) {
+    SwingUtil.resetCaption ( okButton, captionMap.get(OK_BUTTON) );
+    SwingUtil.resetCaption ( applyButton, captionMap.get(APPLY_BUTTON) );
+    SwingUtil.resetCaption ( cancelButton, captionMap.get(CANCEL_BUTTON) );
+    Object caption = captionMap.get( DIALOG_TITLE );
+    if ( caption != null ) {
+      frameTitle = caption.toString();
+      // Damit Layer-Bezeichnung in Titel uebernommen wird, ein MapLayerEvent
+      // ausloesen
+      layer.setTitle( layer.getTitle() );
+    }
+    filterPanel.resetCaptions( captionMap );
+  }
+}

Modified: trunk/src/schmitzm/geotools/gui/FeatureTablePane.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/FeatureTablePane.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/FeatureTablePane.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,419 +1,437 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.gui;
-
-import java.awt.BorderLayout;
-import java.awt.Color;
-import java.awt.Dimension;
-import java.io.IOException;
-
-import javax.swing.BorderFactory;
-import javax.swing.JScrollPane;
-import javax.swing.JSplitPane;
-import javax.swing.JTable;
-import javax.swing.ListSelectionModel;
-import javax.swing.event.ListSelectionEvent;
-import javax.swing.event.ListSelectionListener;
-import javax.swing.event.TableModelEvent;
-import javax.swing.event.TableModelListener;
-import javax.swing.table.TableModel;
-
-import org.apache.log4j.Logger;
-import org.geotools.data.FeatureSource;
-import org.geotools.data.memory.MemoryDataStore;
-import org.geotools.feature.FeatureCollection;
-import org.geotools.map.DefaultMapLayer;
-import org.geotools.styling.Style;
-
-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;
-
-/**
- * Diese Komponente stellt eine Tabelle dar, in der die Attribute einer
- * {@link FeatureCollection} dargestellt werden. Optional werden links neben der
- * Tabelle die in der Tabelle ausgewaehlten Features grafisch dargestellt.<br>
- * <br>
- * <b>Bemerkung:</b><br>
- * Als {@code TableModel} fuer die Feature-Tabelle verwendet diese Klasse ein
- * eigenes internes {@link TableModel}, welches effizienter arbeitet, als
- * {@link org.geotools.gui.swing.table.FeatureTableModel
- * org.geotools.gui.swing.table.FeatureTableModel}.
- * 
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- *         (University of Bonn/Germany)
- * @version 1.0
- */
-public class FeatureTablePane extends JPanel {
-	final static Logger LOGGER = Logger.getLogger(FeatureTablePane.class);
-
-	/** Tabelle in der die Features angezeigt werden. */
-	protected SortableJTable featuresTable = null;
-
-	/** Tabellen-Modell der Feature-Tabelle. */
-	protected FeatureCollectionTableModel featuresTableModel = null;
-	/** Preview-Bereich fuer die in der Tabelle selektierten Features. */
-	protected JMapPane mapPane = null;
-	/** Style, in dem die Features in der Karte dargestellt werden */
-	protected Style featureStyle = null;
-
-	/**
-	 * Constant for the ToolTip of the preview mappane
-	 */
-	public static final String PREVIEW_MAPPANE_TOOLTIP = FeatureTablePane.class
-			.getName()
-			+ ".PreviewMapPaneToolTip";
-
-	/**
-	 * Splitpane, das die Karten-Vorschau von der Tabelle trennt ({@code null}
-	 * wenn Karten-Vorschau deaktiviert ist).
-	 */
-	protected JSplitPane splitPane = null;
-	private JScrollPane featuresTableScrollPane;
-
-	public JScrollPane getFeaturesTableScrollPane() {
-		return featuresTableScrollPane;
-	}
-
-	/**
-	 * Erzeugt einen neue Komponente mit Preview-Bereich.
-	 */
-	public FeatureTablePane() {
-		this(false);
-	}
-
-	/**
-	 * Erzeugt einen neue Komponente mit Preview-Bereich.
-	 * 
-	 * @param fc
-	 *            angezeigte Features
-	 */
-	public FeatureTablePane(FeatureCollection fc) {
-		this(fc, true);
-	}
-
-	/**
-	 * Erzeugt einen neue Komponente.
-	 * 
-	 * @param geomPreview
-	 *            bestimmt, ob ein Preview-Bereich angezeigt wird ({@code true})
-	 *            oder nicht ({@code false})
-	 */
-	public FeatureTablePane(boolean geomPreview) {
-		this(null, geomPreview);
-	}
-
-	/**
-	 * Erzeugt einen neue Komponente.
-	 * 
-	 * @param fc
-	 *            angezeigte Features
-	 * @param geomPreview
-	 *            bestimmt, ob ein Preview-Bereich angezeigt wird ({@code true})
-	 *            oder nicht ({@code false})
-	 */
-	public FeatureTablePane(FeatureCollection fc, boolean geomPreview) {
-		this(fc, null, geomPreview);
-	}
-
-	/**
-	 * Erzeugt einen neue Komponente.
-	 * 
-	 * @param fc
-	 *            angezeigte Features
-	 * @param style
-	 *            Style, in dem die Features in der Karte dargestellt werden
-	 * @param geomPreview
-	 *            bestimmt, ob ein Preview-Bereich angezeigt wird ({@code true})
-	 *            oder nicht ({@code false})
-	 */
-	public FeatureTablePane(FeatureCollection fc, Style style,
-			boolean geomPreview) {
-		this(new FeatureCollectionTableModel(fc), style, geomPreview);
-	}
-
-	/**
-	 * Erzeugt einen neue Komponente.
-	 * 
-	 * @param model
-	 *            verwendetes TableModel (kann {@code null} sein)
-	 * @param fc
-	 *            angezeigte Features
-	 * @param style
-	 *            Style, in dem die Features in der Karte dargestellt werden
-	 * @param geomPreview
-	 *            bestimmt, ob ein Preview-Bereich angezeigt wird ({@code true})
-	 *            oder nicht ({@code false})
-	 */
-	public FeatureTablePane(FeatureCollectionTableModel model, Style style,
-			boolean geomPreview) {
-		super();
-		this.featureStyle = style;
-		this.featuresTableModel = (model != null) ? model
-				: new FeatureCollectionTableModel();
-
-		initGUI(geomPreview);
-
-		featuresTableScrollPane = new JScrollPane(featuresTable,
-				JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
-				JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
-
-		// Komponenten dem Pane hinzufuegen
-		if (mapPane != null) {
-			splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
-			// splitPane.setInnerBorder(null);
-			splitPane.setLeftComponent(mapPane);
-			splitPane.setRightComponent(featuresTableScrollPane);
-			splitPane.setOneTouchExpandable(true);
-
-			// splitPane.setDividerLocation(0.3); // SK: Does not have an
-			// effect because the JSplitPane is not visible yet! Before the
-			// JSplitPane is visible, only the divider location can only be
-			// set in absolute int pixels.
-
-			splitPane.setDividerLocation(mapPane.getPreferredSize().width);
-
-			add(splitPane);
-
-			showFeaturesInMap();
-		} else {
-			add(featuresTableScrollPane);
-		}
-	}
-
-	/**
-	 * Initalisiert die GUI.
-	 * 
-	 * @param geomPreview
-	 *            bestimmt, ob ein Preview-Bereich angezeigt wird ({@code true})
-	 *            oder nicht ({@code false})
-	 */
-	protected void initGUI(boolean geomPreview) {
-		setLayout(new BorderLayout());
-		// MapPane fuer Preview der in der Tabelle selektieren Features
-		if (geomPreview) {
-			this.mapPane = new JMapPane();
-
-			// {
-			// // Bei Links-Klick auf das gesamte Layer zoomen
-			// public void mouseClicked(MouseEvent e) {
-			// if (getState() == JMapPane.RESET && e.getButton() == e.BUTTON1) {
-			// MapLayer layer = getTopLayer();
-			// if (layer != null)
-			// try {
-			// setMapArea(layer.getFeatureSource().getBounds());
-			// refresh();
-			// } catch (Exception err) {
-			// }
-			// } else {
-			// super.mouseClicked(e);
-			// }
-			// }
-			// };
-			mapPane.setToolTipText(GeotoolsGUIUtil.R(PREVIEW_MAPPANE_TOOLTIP));
-
-			mapPane.setState(JMapPane.RESET);
-			mapPane.setWindowSelectionState(JMapPane.NONE);
-			mapPane.setHighlight(false);
-			mapPane.setMinimumSize(new Dimension(100, 100));
-			SwingUtil.setPreferredWidth(mapPane, 200);
-			mapPane.setBorder(BorderFactory.createLoweredBevelBorder());
-
-		}
-
-		// Tabelle fuer FeatureCollection
-		featuresTable = new SortableJTable();
-
-		featuresTable.setModel(featuresTableModel);
-		featuresTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
-		featuresTable.setColumnSelectionAllowed(false);
-		featuresTable
-				.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
-		// Wenn Auswahl in Tabelle sich aendert, Vorschau anpassen
-		featuresTable.getSelectionModel().addListSelectionListener(
-				new ListSelectionListener() {
-					public void valueChanged(ListSelectionEvent e) {
-						if (!e.getValueIsAdjusting())
-							performListSelection();
-					}
-				});
-
-		// Wenn neue FeatureCollection gesetzt wird, werden trotzdem nur die
-		// selektierten rot angezeigt. Der rest grau.
-		featuresTableModel.addTableModelListener(new TableModelListener() {
-			public void tableChanged(TableModelEvent e) {
-				// showFeaturesInMap(getSelectedFeatures());
-				if (mapPane != null) {
-					// falls diese TableContextChange durch einen neu
-					// angewendeten filter passiert ist, soll sich auch das
-					// hintergund layer ändern.
-					mapPane.getContext().clearLayerList();
-				}
-				showFeaturesInMap();
-			}
-		});
-
-	}
-
-	/**
-	 * Liefert den Filter, der die dargestellten Attribut-Spalten bestimmt.
-	 */
-	public AttributeTypeFilter getAttributeFilter() {
-		return featuresTableModel.getAttributeFilter();
-	}
-
-	/**
-	 * Setzt den Filter, der die dargestellten Attribut-Spalten bestimmt.
-	 * 
-	 * @param attrFilter
-	 *            Filter
-	 */
-	public void setAttributeFilter(AttributeTypeFilter attrFilter) {
-		featuresTableModel.setAttributeFilter(attrFilter);
-	}
-
-	/**
-	 * Prueft, ob der Geometry-Preview angezeigt wird.
-	 */
-	public boolean isGeometryPreviewVisible() {
-		return mapPane != null && mapPane.isVisible();
-	}
-
-	/**
-	 * Setzt die angezeigte {@link FeatureCollection}
-	 * 
-	 * @param fc
-	 *            anzuzeigende Features
-	 */
-	public void setFeatureCollection(FeatureCollection fc) {
-		featuresTableModel.setFeatureCollection(fc);
-	}
-
-	/**
-	 * Liefert die Attribut-Tabelle um deren Eigenschaften (z.B. Spaltenbreite)
-	 * zu aendern.
-	 */
-	public SortableJTable getTable() {
-		return featuresTable;
-	}
-
-	/**
-	 * Liefert die angezeigten Features.
-	 */
-	public FeatureCollection getFeatureCollection() {
-		return featuresTableModel.getFeatureCollection();
-	}
-
-	/**
-	 * Setzt den Style, in dem die Features in der Karte dargestellt werden.
-	 * 
-	 * @param style
-	 *            Style fuer die Features
-	 */
-	public void setFeatureStyle(Style style) {
-		this.featureStyle = style;
-	}
-
-	/**
-	 * Liefert den Style, in dem die Features in der Karte dargestellt werden.
-	 */
-	public Style getFeatureStyle() {
-		return this.featureStyle;
-	}
-
-	/**
-	 * Liefert die in der Tabelle selektierten Features.
-	 */
-	public FeatureCollection getSelectedFeatures() {
-		return featuresTableModel.getFeaturesAsCollection(featuresTable
-				.getSelectedModelRows());
-	}
-
-	/**
-	 * Zeigt die aktuell in der Tabelle selektierten Features in rot im
-	 * Preview-Bereich an.
-	 */
-	protected void performListSelection() {
-		// FeatureCollection subCollection = getSelectedFeatures();
-		// // Wenn keine Auswahl getaetigt ist, alle Features anzeigen
-		// if (subCollection == null || subCollection.isEmpty())
-		// subCollection = getFeatureCollection();
-		showFeaturesInMap();
-	}
-
-	/**
-	 * Zeigt einen die übergebene {@link FeatureCollection} rot in der Karte an.
-	 * Darunter liegen in grau alle Features. Diese Funktion hat keinen Einfluss
-	 * auf die in der Tabelle angezeigten Features!!
-	 * 
-	 * @param fc
-	 *            eine {@link FeatureCollection}
-	 */
-	protected void showFeaturesInMap() {
-		if (mapPane == null)
-			return;
-
-		FeatureCollection selectedFeatures = getSelectedFeatures();
-
-		/**
-		 * Das layer mit allen features soll nicht immer neu eingefügt werden.
-		 * Deshalb wird es nur einmal eingefügt.
-		 */
-		if (mapPane.getContext().getLayerCount() == 0) {
-
-			final FeatureCollection allFeatures = getFeatureCollection();
-
-			/**
-			 * Add ALL features to the JMapPane as the base layer and style them
-			 * in grey
-			 */
-			if (allFeatures != null && mapPane != null) {
-				
-				mapPane.getContext().addLayer(
-						new DefaultMapLayer(FeatureUtil.createMemoryFeatureSource(allFeatures), StylingUtil
-								.createStyleSimple(allFeatures,
-										Color.lightGray, Color.darkGray)));
-			}
-		}
-
-		// Das zweite Layer entfernen (wenn es schon vorhanden ist)
-		if (mapPane.getContext().getLayerCount() > 1)
-			mapPane.getContext().removeLayer(1);
-
-		// Und ggf. neu hinzufügen
-		if (selectedFeatures != null && selectedFeatures.size() > 0  &&
-		    selectedFeatures.getSchema().getDefaultGeometry() != null) {
-
-			if (getFeatureStyle() == null) {
-				setFeatureStyle(StylingUtil.createStyleSimple(selectedFeatures,
-						Color.red, Color.white));
-			}
-			mapPane.getContext().addLayer(selectedFeatures, getFeatureStyle());
-
-			/**
-			 * TODO Das schmeisst eine blöde exception
-			 * java.lang.UnsupportedOperationException: Unbekanntes
-			 * Feature-Attribut: POP2002 at
-			 * schmitzm.geotools.feature.FeatureOperationTree
-			 * .evaluate(FeatureOperationTree.java:92) at
-			 * schmitzm.lang.tree.OperationTree.evaluate(OperationTree.java:181)
-			 */
-			//mapPane.zoomTo(getFeatureCollection()); //
-		}
-
-		// Vorschaukarte aktualisieren
-		mapPane.refresh();
-	}
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.gui;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Dimension;
+import java.io.IOException;
+
+import javax.swing.BorderFactory;
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+import javax.swing.JTable;
+import javax.swing.ListSelectionModel;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+import javax.swing.event.TableModelEvent;
+import javax.swing.event.TableModelListener;
+import javax.swing.table.TableModel;
+
+import org.apache.log4j.Logger;
+import org.geotools.data.FeatureSource;
+import org.geotools.data.memory.MemoryDataStore;
+import org.geotools.feature.FeatureCollection;
+import org.geotools.map.DefaultMapLayer;
+import org.geotools.styling.Style;
+
+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;
+
+/**
+ * Diese Komponente stellt eine Tabelle dar, in der die Attribute einer
+ * {@link FeatureCollection} dargestellt werden. Optional werden links neben der
+ * Tabelle die in der Tabelle ausgewaehlten Features grafisch dargestellt.<br>
+ * <br>
+ * <b>Bemerkung:</b><br>
+ * Als {@code TableModel} fuer die Feature-Tabelle verwendet diese Klasse ein
+ * eigenes internes {@link TableModel}, welches effizienter arbeitet, als
+ * {@link org.geotools.gui.swing.table.FeatureTableModel
+ * org.geotools.gui.swing.table.FeatureTableModel}.
+ * 
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *         (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class FeatureTablePane extends JPanel {
+	final static Logger LOGGER = Logger.getLogger(FeatureTablePane.class);
+
+	/** Tabelle in der die Features angezeigt werden. */
+	protected SortableJTable featuresTable = null;
+
+	/** Tabellen-Modell der Feature-Tabelle. */
+	protected FeatureCollectionTableModel featuresTableModel = null;
+	/** Preview-Bereich fuer die in der Tabelle selektierten Features. */
+	protected JMapPane mapPane = null;
+	/** Style, in dem die Features in der Karte dargestellt werden */
+	protected Style featureStyle = null;
+
+	/**
+	 * Constant for the ToolTip of the preview mappane
+	 */
+	public static final String PREVIEW_MAPPANE_TOOLTIP = FeatureTablePane.class
+			.getName()
+			+ ".PreviewMapPaneToolTip";
+
+	/**
+	 * Splitpane, das die Karten-Vorschau von der Tabelle trennt ({@code null}
+	 * wenn Karten-Vorschau deaktiviert ist).
+	 */
+	protected JSplitPane splitPane = null;
+	private JScrollPane featuresTableScrollPane;
+
+	public JScrollPane getFeaturesTableScrollPane() {
+		return featuresTableScrollPane;
+	}
+
+	/**
+	 * Erzeugt einen neue Komponente mit Preview-Bereich.
+	 */
+	public FeatureTablePane() {
+		this(false);
+	}
+
+	/**
+	 * Erzeugt einen neue Komponente mit Preview-Bereich.
+	 * 
+	 * @param fc
+	 *            angezeigte Features
+	 */
+	public FeatureTablePane(FeatureCollection fc) {
+		this(fc, true);
+	}
+
+	/**
+	 * Erzeugt einen neue Komponente.
+	 * 
+	 * @param geomPreview
+	 *            bestimmt, ob ein Preview-Bereich angezeigt wird ({@code true})
+	 *            oder nicht ({@code false})
+	 */
+	public FeatureTablePane(boolean geomPreview) {
+		this(null, geomPreview);
+	}
+
+	/**
+	 * Erzeugt einen neue Komponente.
+	 * 
+	 * @param fc
+	 *            angezeigte Features
+	 * @param geomPreview
+	 *            bestimmt, ob ein Preview-Bereich angezeigt wird ({@code true})
+	 *            oder nicht ({@code false})
+	 */
+	public FeatureTablePane(FeatureCollection fc, boolean geomPreview) {
+		this(fc, null, geomPreview);
+	}
+
+	/**
+	 * Erzeugt einen neue Komponente.
+	 * 
+	 * @param fc
+	 *            angezeigte Features
+	 * @param style
+	 *            Style, in dem die Features in der Karte dargestellt werden
+	 * @param geomPreview
+	 *            bestimmt, ob ein Preview-Bereich angezeigt wird ({@code true})
+	 *            oder nicht ({@code false})
+	 */
+	public FeatureTablePane(FeatureCollection fc, Style style,
+			boolean geomPreview) {
+		this(new FeatureCollectionTableModel(fc), style, geomPreview);
+	}
+
+	/**
+	 * Erzeugt einen neue Komponente.
+	 * 
+	 * @param model
+	 *            verwendetes TableModel (kann {@code null} sein)
+	 * @param fc
+	 *            angezeigte Features
+	 * @param style
+	 *            Style, in dem die Features in der Karte dargestellt werden
+	 * @param geomPreview
+	 *            bestimmt, ob ein Preview-Bereich angezeigt wird ({@code true})
+	 *            oder nicht ({@code false})
+	 */
+	public FeatureTablePane(FeatureCollectionTableModel model, Style style,
+			boolean geomPreview) {
+		super();
+		this.featureStyle = style;
+		this.featuresTableModel = (model != null) ? model
+				: new FeatureCollectionTableModel();
+
+		initGUI(geomPreview);
+
+		featuresTableScrollPane = new JScrollPane(featuresTable,
+				JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
+				JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+
+		// Komponenten dem Pane hinzufuegen
+		if (mapPane != null) {
+			splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
+			// splitPane.setInnerBorder(null);
+			splitPane.setLeftComponent(mapPane);
+			splitPane.setRightComponent(featuresTableScrollPane);
+			splitPane.setOneTouchExpandable(true);
+
+			// splitPane.setDividerLocation(0.3); // SK: Does not have an
+			// effect because the JSplitPane is not visible yet! Before the
+			// JSplitPane is visible, only the divider location can only be
+			// set in absolute int pixels.
+
+			splitPane.setDividerLocation(mapPane.getPreferredSize().width);
+
+			add(splitPane);
+
+			showFeaturesInMap();
+		} else {
+			add(featuresTableScrollPane);
+		}
+	}
+
+	/**
+	 * Initalisiert die GUI.
+	 * 
+	 * @param geomPreview
+	 *            bestimmt, ob ein Preview-Bereich angezeigt wird ({@code true})
+	 *            oder nicht ({@code false})
+	 */
+	protected void initGUI(boolean geomPreview) {
+		setLayout(new BorderLayout());
+		// MapPane fuer Preview der in der Tabelle selektieren Features
+		if (geomPreview) {
+			this.mapPane = new JMapPane();
+
+			// {
+			// // Bei Links-Klick auf das gesamte Layer zoomen
+			// public void mouseClicked(MouseEvent e) {
+			// if (getState() == JMapPane.RESET && e.getButton() == e.BUTTON1) {
+			// MapLayer layer = getTopLayer();
+			// if (layer != null)
+			// try {
+			// setMapArea(layer.getFeatureSource().getBounds());
+			// refresh();
+			// } catch (Exception err) {
+			// }
+			// } else {
+			// super.mouseClicked(e);
+			// }
+			// }
+			// };
+			mapPane.setToolTipText(GeotoolsGUIUtil.R(PREVIEW_MAPPANE_TOOLTIP));
+
+			mapPane.setState(JMapPane.RESET);
+			mapPane.setWindowSelectionState(JMapPane.NONE);
+			mapPane.setHighlight(false);
+			mapPane.setMinimumSize(new Dimension(100, 100));
+			SwingUtil.setPreferredWidth(mapPane, 200);
+			mapPane.setBorder(BorderFactory.createLoweredBevelBorder());
+
+		}
+
+		// Tabelle fuer FeatureCollection
+		featuresTable = new SortableJTable();
+
+		featuresTable.setModel(featuresTableModel);
+		featuresTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
+		featuresTable.setColumnSelectionAllowed(false);
+		featuresTable
+				.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
+		// Wenn Auswahl in Tabelle sich aendert, Vorschau anpassen
+		featuresTable.getSelectionModel().addListSelectionListener(
+				new ListSelectionListener() {
+					public void valueChanged(ListSelectionEvent e) {
+						if (!e.getValueIsAdjusting())
+							performListSelection();
+					}
+				});
+
+		// Wenn neue FeatureCollection gesetzt wird, werden trotzdem nur die
+		// selektierten rot angezeigt. Der rest grau.
+		featuresTableModel.addTableModelListener(new TableModelListener() {
+			public void tableChanged(TableModelEvent e) {
+				// showFeaturesInMap(getSelectedFeatures());
+				if (mapPane != null) {
+					// falls diese TableContextChange durch einen neu
+					// angewendeten filter passiert ist, soll sich auch das
+					// hintergund layer ändern.
+					mapPane.getContext().clearLayerList();
+				}
+				showFeaturesInMap();
+			}
+		});
+
+	}
+
+	/**
+	 * Liefert den Filter, der die dargestellten Attribut-Spalten bestimmt.
+	 */
+	public AttributeTypeFilter getAttributeFilter() {
+		return featuresTableModel.getAttributeFilter();
+	}
+
+	/**
+	 * Setzt den Filter, der die dargestellten Attribut-Spalten bestimmt.
+	 * 
+	 * @param attrFilter
+	 *            Filter
+	 */
+	public void setAttributeFilter(AttributeTypeFilter attrFilter) {
+		featuresTableModel.setAttributeFilter(attrFilter);
+	}
+
+	/**
+	 * Prueft, ob der Geometry-Preview angezeigt wird.
+	 */
+	public boolean isGeometryPreviewVisible() {
+		return mapPane != null && mapPane.isVisible();
+	}
+
+	/**
+	 * Setzt die angezeigte {@link FeatureCollection}
+	 * 
+	 * @param fc
+	 *            anzuzeigende Features
+	 */
+	public void setFeatureCollection(FeatureCollection fc) {
+		featuresTableModel.setFeatureCollection(fc);
+	}
+
+	/**
+	 * Liefert die Attribut-Tabelle um deren Eigenschaften (z.B. Spaltenbreite)
+	 * zu aendern.
+	 */
+	public SortableJTable getTable() {
+		return featuresTable;
+	}
+
+	/**
+	 * Liefert die angezeigten Features.
+	 */
+	public FeatureCollection getFeatureCollection() {
+		return featuresTableModel.getFeatureCollection();
+	}
+
+	/**
+	 * Setzt den Style, in dem die Features in der Karte dargestellt werden.
+	 * 
+	 * @param style
+	 *            Style fuer die Features
+	 */
+	public void setFeatureStyle(Style style) {
+		this.featureStyle = style;
+	}
+
+	/**
+	 * Liefert den Style, in dem die Features in der Karte dargestellt werden.
+	 */
+	public Style getFeatureStyle() {
+		return this.featureStyle;
+	}
+
+	/**
+	 * Liefert die in der Tabelle selektierten Features.
+	 */
+	public FeatureCollection getSelectedFeatures() {
+		return featuresTableModel.getFeaturesAsCollection(featuresTable
+				.getSelectedModelRows());
+	}
+
+	/**
+	 * Zeigt die aktuell in der Tabelle selektierten Features in rot im
+	 * Preview-Bereich an.
+	 */
+	protected void performListSelection() {
+		// FeatureCollection subCollection = getSelectedFeatures();
+		// // Wenn keine Auswahl getaetigt ist, alle Features anzeigen
+		// if (subCollection == null || subCollection.isEmpty())
+		// subCollection = getFeatureCollection();
+		showFeaturesInMap();
+	}
+
+	/**
+	 * Zeigt einen die übergebene {@link FeatureCollection} rot in der Karte an.
+	 * Darunter liegen in grau alle Features. Diese Funktion hat keinen Einfluss
+	 * auf die in der Tabelle angezeigten Features!!
+	 * 
+	 * @param fc
+	 *            eine {@link FeatureCollection}
+	 */
+	protected void showFeaturesInMap() {
+		if (mapPane == null)
+			return;
+
+		FeatureCollection selectedFeatures = getSelectedFeatures();
+
+		/**
+		 * Das layer mit allen features soll nicht immer neu eingefügt werden.
+		 * Deshalb wird es nur einmal eingefügt.
+		 */
+		if (mapPane.getContext().getLayerCount() == 0) {
+
+			final FeatureCollection allFeatures = getFeatureCollection();
+
+			/**
+			 * Add ALL features to the JMapPane as the base layer and style them
+			 * in grey
+			 */
+			if (allFeatures != null && mapPane != null) {
+				
+				mapPane.getContext().addLayer(
+						new DefaultMapLayer(FeatureUtil.createMemoryFeatureSource(allFeatures), StylingUtil
+								.createStyleSimple(allFeatures,
+										Color.lightGray, Color.darkGray)));
+			}
+		}
+
+		// Das zweite Layer entfernen (wenn es schon vorhanden ist)
+		if (mapPane.getContext().getLayerCount() > 1)
+			mapPane.getContext().removeLayer(1);
+
+		// Und ggf. neu hinzufügen
+		if (selectedFeatures != null && selectedFeatures.size() > 0  &&
+		    selectedFeatures.getSchema().getDefaultGeometry() != null) {
+
+			if (getFeatureStyle() == null) {
+				setFeatureStyle(StylingUtil.createStyleSimple(selectedFeatures,
+						Color.red, Color.white));
+			}
+			mapPane.getContext().addLayer(selectedFeatures, getFeatureStyle());
+
+			/**
+			 * TODO Das schmeisst eine blöde exception
+			 * java.lang.UnsupportedOperationException: Unbekanntes
+			 * Feature-Attribut: POP2002 at
+			 * schmitzm.geotools.feature.FeatureOperationTree
+			 * .evaluate(FeatureOperationTree.java:92) at
+			 * schmitzm.lang.tree.OperationTree.evaluate(OperationTree.java:181)
+			 */
+			//mapPane.zoomTo(getFeatureCollection()); //
+		}
+
+		// Vorschaukarte aktualisieren
+		mapPane.refresh();
+	}
+}

Modified: trunk/src/schmitzm/geotools/gui/FeatureTypeInputOption.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/FeatureTypeInputOption.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/FeatureTypeInputOption.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,107 +1,126 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.geotools.gui;
-
-import javax.swing.JScrollPane;
-import javax.swing.ListSelectionModel;
-
-import org.geotools.feature.FeatureType;
-
-import schmitzm.geotools.feature.FeatureTypeBuilderTableModel;
-import schmitzm.swing.InputOption;
-import schmitzm.swing.MultipleOptionPane;
-import schmitzm.swing.SwingUtil;
-import schmitzm.swing.table.MutableTable;
-
-/**
- * {@linkplain InputOption Eingabe-Option} zur Definition eines {@link FeatureType} im
- * {@link MultipleOptionPane}.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- */
-public class FeatureTypeInputOption extends InputOption<FeatureType> {
-  /** Beinhaltet die Tabelle, in der die Attribute eingegeben
-   *  werden. */
-  protected MutableTable inpTable;
-  /** Beinhaltet das Tabellen-Modell, in dem die Attribute verwaltet
-   *  werden. */
-  protected FeatureTypeBuilderTableModel inpTableModel;
-
-  /**
-   * Erzeugt einen neue Eingabe-Option.
-   * @param label Ueberschrift
-   * @param inputNeeded bestimmt, ob eine Eingabe erforderlich ist
-   */
-  public FeatureTypeInputOption(String label, boolean inputNeeded) {
-    this(label, inputNeeded, null);
-  }
-
-
-  /**
-   * Erzeugt einen neue Eingabe-Option.
-   * @param label Ueberschrift
-   * @param inputNeeded bestimmt, ob eine Eingabe erforderlich ist
-   * @param fType initalial dargestellter {@link FeatureType} (kann {@code null} sein)
-   */
-  public FeatureTypeInputOption(String label, boolean inputNeeded, FeatureType fType) {
-    super(label, inputNeeded, true);
-    if (fType != null)
-      setValue(fType);
-  }
-
-  /**
-   * Erzeugt eine neue Instanz der Eingabe-Komponente. z.B. ein Text-Eingabefeld
-   * oder eine Combo-Box.
-   */
-  protected JScrollPane createInputComponent() {
-    this.inpTableModel = new FeatureTypeBuilderTableModel();
-    this.inpTable      = new MutableTable( inpTableModel, MutableTable.ITEM_ADD | MutableTable.ITEM_REMOVE );
-    this.inpTable.setColumnSelectionAllowed(false);
-    this.inpTable.setSelectionMode( ListSelectionModel.MULTIPLE_INTERVAL_SELECTION );
-    SwingUtil.setPreferredHeight(this,200);
-    SwingUtil.setPreferredWidth(this,400);
-    return new JScrollPane(inpTable);
-  }
-
-  /**
-   * Liefert den aktuellen in der Tabelle definierten {@link FeatureType}.
-   */
-  protected FeatureType performGetValue() {
-    return inpTableModel.createFeatureType();
-  }
-  /**
-   * Initalisiert die Tabelle mit einem neuen {@link FeatureType}.
-   * @param newValue neuer {@link FeatureType}
-   * @return immer {@code true}
-   */
-  protected boolean performSetValue(FeatureType newValue) {
-    inpTableModel.setFeatureType(newValue);
-    return true;
-  }
-
-  /**
-   * Prueft, ob ein Attribut definiert ist.
-   */
-  protected boolean performIsInputEmpty() {
-    return inpTable.getRowCount() == 0;
-  }
-
-  /**
-   * Prueft, ob die aktuelle Eingabe leer ist. Wirft eine Exception
-   * wenn {@link FeatureTypeBuilderTableModel#createFeatureType()}
-   * eine Exception wirft.
-   * @return immer {@code true}
-   */
-  protected boolean performIsInputValid() {
-    inpTableModel.createFeatureType();
-    return true;
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.gui;
+
+import javax.swing.JScrollPane;
+import javax.swing.ListSelectionModel;
+
+import org.geotools.feature.FeatureType;
+
+import schmitzm.geotools.feature.FeatureTypeBuilderTableModel;
+import schmitzm.swing.InputOption;
+import schmitzm.swing.MultipleOptionPane;
+import schmitzm.swing.SwingUtil;
+import schmitzm.swing.table.MutableTable;
+
+/**
+ * {@linkplain InputOption Eingabe-Option} zur Definition eines {@link FeatureType} im
+ * {@link MultipleOptionPane}.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ */
+public class FeatureTypeInputOption extends InputOption<FeatureType> {
+  /** Beinhaltet die Tabelle, in der die Attribute eingegeben
+   *  werden. */
+  protected MutableTable inpTable;
+  /** Beinhaltet das Tabellen-Modell, in dem die Attribute verwaltet
+   *  werden. */
+  protected FeatureTypeBuilderTableModel inpTableModel;
+
+  /**
+   * Erzeugt einen neue Eingabe-Option.
+   * @param label Ueberschrift
+   * @param inputNeeded bestimmt, ob eine Eingabe erforderlich ist
+   */
+  public FeatureTypeInputOption(String label, boolean inputNeeded) {
+    this(label, inputNeeded, null);
+  }
+
+
+  /**
+   * Erzeugt einen neue Eingabe-Option.
+   * @param label Ueberschrift
+   * @param inputNeeded bestimmt, ob eine Eingabe erforderlich ist
+   * @param fType initalial dargestellter {@link FeatureType} (kann {@code null} sein)
+   */
+  public FeatureTypeInputOption(String label, boolean inputNeeded, FeatureType fType) {
+    super(label, inputNeeded, true);
+    if (fType != null)
+      setValue(fType);
+  }
+
+  /**
+   * Erzeugt eine neue Instanz der Eingabe-Komponente. z.B. ein Text-Eingabefeld
+   * oder eine Combo-Box.
+   */
+  protected JScrollPane createInputComponent() {
+    this.inpTableModel = new FeatureTypeBuilderTableModel();
+    this.inpTable      = new MutableTable( inpTableModel, MutableTable.ITEM_ADD | MutableTable.ITEM_REMOVE );
+    this.inpTable.setColumnSelectionAllowed(false);
+    this.inpTable.setSelectionMode( ListSelectionModel.MULTIPLE_INTERVAL_SELECTION );
+    SwingUtil.setPreferredHeight(this,200);
+    SwingUtil.setPreferredWidth(this,400);
+    return new JScrollPane(inpTable);
+  }
+
+  /**
+   * Liefert den aktuellen in der Tabelle definierten {@link FeatureType}.
+   */
+  protected FeatureType performGetValue() {
+    return inpTableModel.createFeatureType();
+  }
+  /**
+   * Initalisiert die Tabelle mit einem neuen {@link FeatureType}.
+   * @param newValue neuer {@link FeatureType}
+   * @return immer {@code true}
+   */
+  protected boolean performSetValue(FeatureType newValue) {
+    inpTableModel.setFeatureType(newValue);
+    return true;
+  }
+
+  /**
+   * Prueft, ob ein Attribut definiert ist.
+   */
+  protected boolean performIsInputEmpty() {
+    return inpTable.getRowCount() == 0;
+  }
+
+  /**
+   * Prueft, ob die aktuelle Eingabe leer ist. Wirft eine Exception
+   * wenn {@link FeatureTypeBuilderTableModel#createFeatureType()}
+   * eine Exception wirft.
+   * @return immer {@code true}
+   */
+  protected boolean performIsInputValid() {
+    inpTableModel.createFeatureType();
+    return true;
+  }
+
+}

Modified: trunk/src/schmitzm/geotools/gui/GeoMapPane.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/GeoMapPane.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/GeoMapPane.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,330 +1,348 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.gui;
-
-import java.awt.Color;
-import java.awt.Dimension;
-import java.awt.Graphics;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-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.map.event.JMapPaneEvent;
-import schmitzm.geotools.map.event.JMapPaneListener;
-import schmitzm.geotools.map.event.MapAreaChangedEvent;
-import schmitzm.geotools.map.event.ScaleChangedEvent;
-import schmitzm.swing.JPanel;
-import schmitzm.swing.SwingUtil;
-
-/**
- * Das {@code GeoMapPane} erweitert das {@link JMapPane} um einen
- * Massstab-Balken, sowie ein horizontales und vertikales Koordinaten-Raster
- * (Grid), in dem die Geo-Referenz des angezeigten Karten-Bereichs in
- * Welt-Koordinaten (Grad, Minuten) dargestellt ist.
- * 
- * @see ScalePane
- * @see GridPanel
- * @author Martin Schmitz
- * @version 1.0
- */
-public class GeoMapPane extends JPanel {
-
-
-	/**
-	 * Konstante fuer das vertikale Koordinaten-Grid.
-	 * 
-	 * @see #layoutConstraints
-	 */
-	public static final String DLC_VGRID = "vertGrid";
-	/**
-	 * Konstante fuer das horizontale Koordinaten-Grid.
-	 * 
-	 * @see #layoutConstraints
-	 */
-	public static final String DLC_HGRID = "horGrid";
-	/**
-	 * Konstante fuer die Karte.
-	 * 
-	 * @see #layoutConstraints
-	 */
-	public static final String DLC_MAP = "mapPane";
-	/**
-	 * Konstante fuer den Massstab-Balken.
-	 * 
-	 * @see #layoutConstraints
-	 */
-	public static final String DLC_SCALE = "scalePane";
-	/**
-	 * Werte fuer die grafische Anordnung der Layout-Komponenten. Ueber die
-	 * Konstanten {@link #DLC_MAP}, {@link #DLC_VGRID}, {@link #DLC_HGRID} und
-	 * {@link #DLC_SCALE} koennen die Constraints (am Anfang von
-	 * {@link #guiInit()}) veraendert oder erweitert werden.
-	 */
-	protected HashMap<String, GridBagConstraints> layoutConstraints = new HashMap<String, GridBagConstraints>();
-
-	/** Karten-Bereich des {@code GeoMapPane}. */
-	protected JMapPane mapPane = null;
-	/** Massstab-Balken */
-	protected ScalePane scalePane = null;
-	/**
-	 * Vertikale Koordinaten-Leiste (Grid). Zeigt die Latitude-Koordinate in
-	 * Grad und Minutenm an.
-	 */
-	protected GridPanel vertGrid = null;
-	/**
-	 * Horizontale Koordinaten-Leiste (Grid). Zeigt die Longitude-Koordinate in
-	 * Grad und Minutenm an.
-	 */
-	protected GridPanel horGrid = null;
-
-	/**
-	 * A flag indicating if dispose() was already called. If true, then further
-	 * use of this {@link GeoMapPane} is undefined.
-	 */
-	private boolean disposed = false;
-
-	/**
-	 * Erzeugt ein neues {@code GeoMapPane}.
-	 */
-	public GeoMapPane() {
-		this(null, null, null, null, null);
-	}
-
-	/**
-	 * Erzeugt ein neues {@code GeoMapPane}. Dieser Konstruktor bietet die
-	 * Moeglichkeit, alternative Implementierungen der einzelnen Komponenten
-	 * darzustellen. <b>Die uebergebenen Parameter koennen {@code null} sein! In
-	 * diesem Fall wird die entsprechende Standard-Implementierung
-	 * verwendet.</b>
-	 * 
-	 * @param mapPane
-	 *            Karten-Bereich
-	 * @param vGrid
-	 *            vertikales Koordinaten-Raster
-	 * @param hGrid
-	 *            horizontales Koordinaten-Raster
-	 * @param scalePane
-	 *            Massstab-Balken
-	 * @param renderer
-	 *            Allows you to choose between the {@link StreamingRenderer}
-	 *            which is cool for creating PDF, SVG.. And the much faster
-	 *            {@link ShapefileRenderer}.
-	 */
-	public GeoMapPane(JMapPane mapPane, GridPanel vGrid, GridPanel hGrid,
-			ScalePane scalePane, GTRenderer renderer) {
-		super();
-
-		if (vGrid != null && !vGrid.isVertical())
-			throw new IllegalArgumentException(
-					"GridPanel for vertical grid must be of type GridPanel.VERTICAL!!");
-		if (hGrid != null && !hGrid.isHorizontal())
-			throw new IllegalArgumentException(
-					"GridPanel for horizontal grid must be of type GridPanel.HORIZONTAL!!");
-
-		// Karte
-		this.mapPane = (mapPane != null) ? mapPane : new JMapPane(null,null,renderer, null);
-		// Koordinaten-Leisten
-		this.vertGrid = (vGrid != null) ? vGrid : new GridPanel(
-				GridPanel.VERTICAL, this.mapPane);
-		this.horGrid = (hGrid != null) ? hGrid : new GridPanel(
-				GridPanel.HORIZONTAL, this.mapPane);
-		// Massstab-Balken
-		this.scalePane = (scalePane != null) ? scalePane : new ScalePane();
-
-		// Standard-Werte fuer GUI-Anordnung setzen
-		layoutConstraints.put(DLC_MAP, new GridBagConstraints(1, 0, 1, 1, 1.0,
-				1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH,
-				new Insets(0, 0, 0, 0), 0, 0));
-		layoutConstraints.put(DLC_VGRID, new GridBagConstraints(0, 0, 1, 1,
-				0.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH,
-				new Insets(0, 0, 0, 0), 0, 0));
-		layoutConstraints.put(DLC_HGRID, new GridBagConstraints(1, 1, 1, 1,
-				1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH,
-				new Insets(0, 0, 0, 0), 0, 0));
-		layoutConstraints.put(DLC_SCALE, new GridBagConstraints(1, 2, 1, 1,
-				0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.BOTH,
-				new Insets(2, 5, 2, 5), 0, 0));
-		// GUI initialisieren
-		guiInit();
-	}
-
-	/**
-	 * Wird vom Konstruktor aufgerufen und initialisiert die grafische
-	 * Darstellung/Anordnung der einzelnen GUI-Komponenten in einem
-	 * {@link GridBagLayout}. Die Constraints fuer die Anordnung der Komponenten
-	 * sind in {@link #layoutConstraints} hinterlegt und koennen zu beginn
-	 * dieser Methode ueberschrieben oder erweitert werden.
-	 */
-	protected void guiInit() {
-		this.setLayout(new GridBagLayout());
-
-		// Karten-Darestellung initialisieren
-		this.mapPane.setBorder(BorderFactory.createLoweredBevelBorder());
-		SwingUtil.setPreferredWidth(this.mapPane, 200);
-
-		// MapListener that listens to Scale and MapArea changes
-		this.mapPane.addMapPaneListener(new JMapPaneListener() {
-			public void performMapPaneEvent(JMapPaneEvent e) {
-				if (e instanceof ScaleChangedEvent) {
-					ScaleChangedEvent sce = (ScaleChangedEvent) e;
-					scalePane.setScale(sce.getNewScale());
-				}
-				if (e instanceof MapAreaChangedEvent) {
-					vertGrid.repaint();
-					horGrid.repaint();
-				}
-			}
-		});
-
-		// Komponenten in Layout anordnen
-		this.add(vertGrid, layoutConstraints.get(DLC_VGRID));
-		this.add(horGrid, layoutConstraints.get(DLC_HGRID));
-		this.add(scalePane, layoutConstraints.get(DLC_SCALE));
-		// WICHTIG: mapPane als LETZTES einfuegen, damit es beim Re-Paint ALS
-		// ERSTES
-		// aktualisiert wird und die Aenderungen (Area, Scale) im
-		// Update des Massstab-Balken und der der Koordinaten-Leiste
-		// bereits zur Verfuegung stehen!
-		this.add(mapPane, layoutConstraints.get(DLC_MAP));
-
-		// // Hintergrundfarbe aller enthaltenen Komponenten auf Weiss setzen
-		// setBackground(BGCOLOR, true);
-	}
-
-	/**
-	 * Aktualisiert die Karten-Darstellung.
-	 * 
-	 * @see JMapPane#refresh()
-	 */
-	public void refreshMap() {
-		mapPane.refresh();
-	}
-
-	/**
-	 * Nach dem {@code super}-Aufruf, wird der Massstab neu gesetzt (und somit
-	 * neu angezeigt), falls sich der Massstab der Karte geaendert hat. Dies ist
-	 * ein Workaround, damit der Massstab auch beim allerersten anzeigen korrekt
-	 * angezeigt wird (ohne {@link ScaleChangedEvent}).
-	 */
-	public void paint(Graphics g) {
-		super.paint(g);
-		if (scalePane.getScaleInMeters() != mapPane.getScale()
-				&& mapPane.getScale() > 0)
-			scalePane.setScale(mapPane.getScale());
-	}
-
-	/**
-	 * Liefert das {@link JMapPane}, in dem die Karten dargestellt werden.
-	 */
-	public final JMapPane getMapPane() {
-		return mapPane;
-	}
-
-	/**
-	 * Liefert den {@link MapContext} der die einzelnen Karten-Layer verwaltet.
-	 */
-	public final MapContext getMapContext() {
-		return mapPane.getContext();
-	}
-
-	/**
-	 * Setzt die Hintergrundfarbe des kompletten {@link GeoMapPane}.
-	 * 
-	 * @param color
-	 *            Hintergrundfarbe
-	 */
-	public void setBackground(Color color) {
-		setBackground(color, true);
-	}
-
-	/**
-	 * @return If dispose() has been called. If
-	 *         <code>true<(code>, further use of this {@link GeoMapPane} is undefined
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public boolean isDisposed() {
-		return disposed;
-	}
-
-	/**
-	 * Should be called when the {@link GeoMapPane} is not needed no more to
-	 * help the GarbageCollector
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public void dispose() {
-		if (isDisposed())
-			return;
-		mapPane.dispose();
-		removeAll();
-		disposed = true;
-	}
-	
-	/**
-	 * Nuetzlich wenn die Componente gedruckt (z.B. wenn ein Screenshot gemacht
-	 * wird) wird. Dann werden wird der Hintergrund auf WEISS gesetzt.
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	@Override
-	public void print(Graphics g) {
-		final Color orig = getBackground();
-		setBackground(Color.WHITE);
-		// wrap in try/finally so that we always restore the state
-		try {
-			super.print(g);
-		} finally {
-			setBackground(orig);
-		}
-	}
-
-	// /**
-	// * Trying to reproduce a bug #37
-	// *
-	// * for explanation and screenshots see the xulu trac
-	// *
-	// * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	// Kr&uuml;ger</a>
-	// */
-	// public static void main(String[] args) throws Exception {
-	// JFrame f = new JFrame();
-	// f.pack();
-	// f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
-	// GeoMapPane gmp = new GeoMapPane();
-	// // FeatureCollection shape = GeoImportUtil.readFeaturesFromShapeFile( new
-	// File("/home/stefan/Desktop/AtlasData/benin_karte_UTM31/admin_boundary_benin_utm.shp")
-	// );
-	// FeatureCollection shape = GeoImportUtil.readFeaturesFromShapeFile( new
-	// File("F:\\Arbeit\\Impetus - ZFL\\Daten\\Neuer Ordner\\admin_boundary_benin_utm.shp")
-	// );
-	// gmp.getMapContext().addLayer( shape,
-	// FeatureUtil.createDefaultStyle(shape) );
-	// f.add( gmp);
-	// gmp.getMapPane().setPreferredSize( new Dimension(400,400));
-	// gmp.refreshMap();
-	// f.pack();
-	// f.setVisible(true);
-	// }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.gui;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+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.map.event.JMapPaneEvent;
+import schmitzm.geotools.map.event.JMapPaneListener;
+import schmitzm.geotools.map.event.MapAreaChangedEvent;
+import schmitzm.geotools.map.event.ScaleChangedEvent;
+import schmitzm.swing.JPanel;
+import schmitzm.swing.SwingUtil;
+
+/**
+ * Das {@code GeoMapPane} erweitert das {@link JMapPane} um einen
+ * Massstab-Balken, sowie ein horizontales und vertikales Koordinaten-Raster
+ * (Grid), in dem die Geo-Referenz des angezeigten Karten-Bereichs in
+ * Welt-Koordinaten (Grad, Minuten) dargestellt ist.
+ * 
+ * @see ScalePane
+ * @see GridPanel
+ * @author Martin Schmitz
+ * @version 1.0
+ */
+public class GeoMapPane extends JPanel {
+
+
+	/**
+	 * Konstante fuer das vertikale Koordinaten-Grid.
+	 * 
+	 * @see #layoutConstraints
+	 */
+	public static final String DLC_VGRID = "vertGrid";
+	/**
+	 * Konstante fuer das horizontale Koordinaten-Grid.
+	 * 
+	 * @see #layoutConstraints
+	 */
+	public static final String DLC_HGRID = "horGrid";
+	/**
+	 * Konstante fuer die Karte.
+	 * 
+	 * @see #layoutConstraints
+	 */
+	public static final String DLC_MAP = "mapPane";
+	/**
+	 * Konstante fuer den Massstab-Balken.
+	 * 
+	 * @see #layoutConstraints
+	 */
+	public static final String DLC_SCALE = "scalePane";
+	/**
+	 * Werte fuer die grafische Anordnung der Layout-Komponenten. Ueber die
+	 * Konstanten {@link #DLC_MAP}, {@link #DLC_VGRID}, {@link #DLC_HGRID} und
+	 * {@link #DLC_SCALE} koennen die Constraints (am Anfang von
+	 * {@link #guiInit()}) veraendert oder erweitert werden.
+	 */
+	protected HashMap<String, GridBagConstraints> layoutConstraints = new HashMap<String, GridBagConstraints>();
+
+	/** Karten-Bereich des {@code GeoMapPane}. */
+	protected JMapPane mapPane = null;
+	/** Massstab-Balken */
+	protected ScalePane scalePane = null;
+	/**
+	 * Vertikale Koordinaten-Leiste (Grid). Zeigt die Latitude-Koordinate in
+	 * Grad und Minutenm an.
+	 */
+	protected GridPanel vertGrid = null;
+	/**
+	 * Horizontale Koordinaten-Leiste (Grid). Zeigt die Longitude-Koordinate in
+	 * Grad und Minutenm an.
+	 */
+	protected GridPanel horGrid = null;
+
+	/**
+	 * A flag indicating if dispose() was already called. If true, then further
+	 * use of this {@link GeoMapPane} is undefined.
+	 */
+	private boolean disposed = false;
+
+	/**
+	 * Erzeugt ein neues {@code GeoMapPane}.
+	 */
+	public GeoMapPane() {
+		this(null, null, null, null, null);
+	}
+
+	/**
+	 * Erzeugt ein neues {@code GeoMapPane}. Dieser Konstruktor bietet die
+	 * Moeglichkeit, alternative Implementierungen der einzelnen Komponenten
+	 * darzustellen. <b>Die uebergebenen Parameter koennen {@code null} sein! In
+	 * diesem Fall wird die entsprechende Standard-Implementierung
+	 * verwendet.</b>
+	 * 
+	 * @param mapPane
+	 *            Karten-Bereich
+	 * @param vGrid
+	 *            vertikales Koordinaten-Raster
+	 * @param hGrid
+	 *            horizontales Koordinaten-Raster
+	 * @param scalePane
+	 *            Massstab-Balken
+	 * @param renderer
+	 *            Allows you to choose between the {@link StreamingRenderer}
+	 *            which is cool for creating PDF, SVG.. And the much faster
+	 *            {@link ShapefileRenderer}.
+	 */
+	public GeoMapPane(JMapPane mapPane, GridPanel vGrid, GridPanel hGrid,
+			ScalePane scalePane, GTRenderer renderer) {
+		super();
+
+		if (vGrid != null && !vGrid.isVertical())
+			throw new IllegalArgumentException(
+					"GridPanel for vertical grid must be of type GridPanel.VERTICAL!!");
+		if (hGrid != null && !hGrid.isHorizontal())
+			throw new IllegalArgumentException(
+					"GridPanel for horizontal grid must be of type GridPanel.HORIZONTAL!!");
+
+		// Karte
+		this.mapPane = (mapPane != null) ? mapPane : new JMapPane(null,null,renderer, null);
+		// Koordinaten-Leisten
+		this.vertGrid = (vGrid != null) ? vGrid : new GridPanel(
+				GridPanel.VERTICAL, this.mapPane);
+		this.horGrid = (hGrid != null) ? hGrid : new GridPanel(
+				GridPanel.HORIZONTAL, this.mapPane);
+		// Massstab-Balken
+		this.scalePane = (scalePane != null) ? scalePane : new ScalePane();
+
+		// Standard-Werte fuer GUI-Anordnung setzen
+		layoutConstraints.put(DLC_MAP, new GridBagConstraints(1, 0, 1, 1, 1.0,
+				1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH,
+				new Insets(0, 0, 0, 0), 0, 0));
+		layoutConstraints.put(DLC_VGRID, new GridBagConstraints(0, 0, 1, 1,
+				0.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH,
+				new Insets(0, 0, 0, 0), 0, 0));
+		layoutConstraints.put(DLC_HGRID, new GridBagConstraints(1, 1, 1, 1,
+				1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH,
+				new Insets(0, 0, 0, 0), 0, 0));
+		layoutConstraints.put(DLC_SCALE, new GridBagConstraints(1, 2, 1, 1,
+				0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.BOTH,
+				new Insets(2, 5, 2, 5), 0, 0));
+		// GUI initialisieren
+		guiInit();
+	}
+
+	/**
+	 * Wird vom Konstruktor aufgerufen und initialisiert die grafische
+	 * Darstellung/Anordnung der einzelnen GUI-Komponenten in einem
+	 * {@link GridBagLayout}. Die Constraints fuer die Anordnung der Komponenten
+	 * sind in {@link #layoutConstraints} hinterlegt und koennen zu beginn
+	 * dieser Methode ueberschrieben oder erweitert werden.
+	 */
+	protected void guiInit() {
+		this.setLayout(new GridBagLayout());
+
+		// Karten-Darestellung initialisieren
+		this.mapPane.setBorder(BorderFactory.createLoweredBevelBorder());
+		SwingUtil.setPreferredWidth(this.mapPane, 200);
+
+		// MapListener that listens to Scale and MapArea changes
+		this.mapPane.addMapPaneListener(new JMapPaneListener() {
+			public void performMapPaneEvent(JMapPaneEvent e) {
+				if (e instanceof ScaleChangedEvent) {
+					ScaleChangedEvent sce = (ScaleChangedEvent) e;
+					scalePane.setScale(sce.getNewScale());
+				}
+				if (e instanceof MapAreaChangedEvent) {
+					vertGrid.repaint();
+					horGrid.repaint();
+				}
+			}
+		});
+
+		// Komponenten in Layout anordnen
+		this.add(vertGrid, layoutConstraints.get(DLC_VGRID));
+		this.add(horGrid, layoutConstraints.get(DLC_HGRID));
+		this.add(scalePane, layoutConstraints.get(DLC_SCALE));
+		// WICHTIG: mapPane als LETZTES einfuegen, damit es beim Re-Paint ALS
+		// ERSTES
+		// aktualisiert wird und die Aenderungen (Area, Scale) im
+		// Update des Massstab-Balken und der der Koordinaten-Leiste
+		// bereits zur Verfuegung stehen!
+		this.add(mapPane, layoutConstraints.get(DLC_MAP));
+
+		// // Hintergrundfarbe aller enthaltenen Komponenten auf Weiss setzen
+		// setBackground(BGCOLOR, true);
+	}
+
+	/**
+	 * Aktualisiert die Karten-Darstellung.
+	 * 
+	 * @see JMapPane#refresh()
+	 */
+	public void refreshMap() {
+		mapPane.refresh();
+	}
+
+	/**
+	 * Nach dem {@code super}-Aufruf, wird der Massstab neu gesetzt (und somit
+	 * neu angezeigt), falls sich der Massstab der Karte geaendert hat. Dies ist
+	 * ein Workaround, damit der Massstab auch beim allerersten anzeigen korrekt
+	 * angezeigt wird (ohne {@link ScaleChangedEvent}).
+	 */
+	public void paint(Graphics g) {
+		super.paint(g);
+		if (scalePane.getScaleInMeters() != mapPane.getScale()
+				&& mapPane.getScale() > 0)
+			scalePane.setScale(mapPane.getScale());
+	}
+
+	/**
+	 * Liefert das {@link JMapPane}, in dem die Karten dargestellt werden.
+	 */
+	public final JMapPane getMapPane() {
+		return mapPane;
+	}
+
+	/**
+	 * Liefert den {@link MapContext} der die einzelnen Karten-Layer verwaltet.
+	 */
+	public final MapContext getMapContext() {
+		return mapPane.getContext();
+	}
+
+	/**
+	 * Setzt die Hintergrundfarbe des kompletten {@link GeoMapPane}.
+	 * 
+	 * @param color
+	 *            Hintergrundfarbe
+	 */
+	public void setBackground(Color color) {
+		setBackground(color, true);
+	}
+
+	/**
+	 * @return If dispose() has been called. If
+	 *         <code>true<(code>, further use of this {@link GeoMapPane} is undefined
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public boolean isDisposed() {
+		return disposed;
+	}
+
+	/**
+	 * Should be called when the {@link GeoMapPane} is not needed no more to
+	 * help the GarbageCollector
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public void dispose() {
+		if (isDisposed())
+			return;
+		mapPane.dispose();
+		removeAll();
+		disposed = true;
+	}
+	
+	/**
+	 * Nuetzlich wenn die Componente gedruckt (z.B. wenn ein Screenshot gemacht
+	 * wird) wird. Dann werden wird der Hintergrund auf WEISS gesetzt.
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	@Override
+	public void print(Graphics g) {
+		final Color orig = getBackground();
+		setBackground(Color.WHITE);
+		// wrap in try/finally so that we always restore the state
+		try {
+			super.print(g);
+		} finally {
+			setBackground(orig);
+		}
+	}
+
+	// /**
+	// * Trying to reproduce a bug #37
+	// *
+	// * for explanation and screenshots see the xulu trac
+	// *
+	// * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	// Kr&uuml;ger</a>
+	// */
+	// public static void main(String[] args) throws Exception {
+	// JFrame f = new JFrame();
+	// f.pack();
+	// f.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
+	// GeoMapPane gmp = new GeoMapPane();
+	// // FeatureCollection shape = GeoImportUtil.readFeaturesFromShapeFile( new
+	// File("/home/stefan/Desktop/AtlasData/benin_karte_UTM31/admin_boundary_benin_utm.shp")
+	// );
+	// FeatureCollection shape = GeoImportUtil.readFeaturesFromShapeFile( new
+	// File("F:\\Arbeit\\Impetus - ZFL\\Daten\\Neuer Ordner\\admin_boundary_benin_utm.shp")
+	// );
+	// gmp.getMapContext().addLayer( shape,
+	// FeatureUtil.createDefaultStyle(shape) );
+	// f.add( gmp);
+	// gmp.getMapPane().setPreferredSize( new Dimension(400,400));
+	// gmp.refreshMap();
+	// f.pack();
+	// f.setVisible(true);
+	// }
+
+}

Modified: trunk/src/schmitzm/geotools/gui/GeoPositionLabel.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/GeoPositionLabel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/GeoPositionLabel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,16 +1,34 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.gui;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.gui;
-
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
 import java.awt.event.MouseMotionListener;
@@ -21,195 +39,195 @@
 import javax.swing.event.MouseInputListener;
 
 import org.geotools.gui.swing.event.GeoMouseEvent;
-
-/**
- * Diese Klasse stellt ein {@link JLabel} dar, in dem (2dimensionale) Geo-Koordinaten
- * angezeigt werden. Dabei werden die Koordinaten auf eine bestimmte Anzahl
- * an Nachkommastellen gerundet.<br>
- * Die Klasse fungiert als {@link MouseListener} und {@link MouseMotionListener} und
- * kann so direkt an ein {@link JMapPane} gekoppelt werden. Die Koordinaten-Darstellung
- * im Label aktualisiert sich somit automatisch, sobald sich die Maus ueber die
- * Karte bewegt. Wird ein Kartenbereich selektiert (gedrueckte linke Maustaste),
- * werden neben der aktuellen Position auch die Koordinaten des Selektionsstart
- * angezeigt.<br>
- * <b>Bemerke:</b><br>
- * Eine Instanz des <code>GeoPositionLabel</code> muss dem {@link JMapPane} sowohl
- * als {@linkplain JMapPane#addMouseListener(MouseListener) MouseListener}, als
- * auch als {@linkplain JMapPane#addMouseMotionListener(MouseMotionListener) MouseMotionListener}
- * hinzugefuegt werden. Ansonsten bekommt es nicht alle notwendigen Informationen
- * mit!
- * @see #setFractionDigits(int)
- * @see #getFractionDigits()
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class GeoPositionLabel extends JLabel implements MouseInputListener {
-
-  // Faktor mit dem die Koordinaten vor dem Runden multipliziert und nach
-  // dem Runden dividiert werden
-  // --> bestimmt die dargestellten Nachkommastellen
-  private double fracFactor = 0.0;
-
-  /** Speichert das Format fuer die dargstellten Koordinaten */
-  protected final DecimalFormat decForm = new DecimalFormat();
-
-  /** Speichert die Koordinaten, die in dem Moment aktuell sind, wenn die linke
-   *  Maustaste gedruckt wird. Und zwar solange, bis die Taste wieder losgelassen
-   *  wird. Danach wieder <code>null</code>. */
-  protected Point2D selStartCoord = null;
-
-  /**
-   * Erzeugt ein neues Label. Die Koordinaten werden ohne Nachkommastellen
-   * dargestellt.
-   */
-  public GeoPositionLabel() {
-    this(0);
-  }
-
-  /**
-   * Erzeugt ein neues Label.
-   * @param fracDigits Anzahl an Nachkommastellen, auf die die Koordinaten gerundet
-   *                   werden
-   */
-  public GeoPositionLabel(final int fracDigits) {
-    super(" ");
-    // eine Stelle vor dem Komma soll immer dargestellt werden
-    this.decForm.setMinimumIntegerDigits(1);
-    // Nachkommastellen setzen
-    this.setFractionDigits(fracDigits);
-  }
-
-  /**
-   * Stellt die Koordinaten im Label dar, wenn es sich bei dem Event um
-   * ein {@link GeoMouseEvent} handelt  oder das Event von einem {@link JMapPane}
-   * ausgeloest wurde.<br>
-   * Wird von {@link #mousePressed(MouseEvent)}, {@link #mouseMoved(MouseEvent)}
-   * und {@link #mouseDragged(MouseEvent)} aufgerufen.
-   * @see #createGeoPositionString(Point2D,Point2D)
-   */
-  protected void displayCoordinates(final MouseEvent e) {
-    if ( e==null || !(e instanceof GeoMouseEvent) && !(e.getSource() instanceof JMapPane) )
-      return;
-
-    // aktuelle Geo-Position ermitteln und runden
-    final Point2D actCoord = JMapPane.getMapCoordinatesFromEvent(e);
-    if ( actCoord == null )
-      return;
-    final double actLat = Math.round(actCoord.getX() * fracFactor) / fracFactor;
-    final double actLon = Math.round(actCoord.getY() * fracFactor) / fracFactor;
-    // Position des Selektion-Startpunkts runden
-    double startLat = 0.0;
-    double startLon = 0.0;
-    if (selStartCoord != null) {
-      startLat = Math.round(selStartCoord.getX() * fracFactor) / fracFactor;
-      startLon = Math.round(selStartCoord.getY() * fracFactor) / fracFactor;
-    }
-    // Label setzen
-    setText(createGeoPositionString(
-        new Point2D.Double(actLat, actLon),
-        selStartCoord == null ? null : new Point2D.Double(startLat, startLon)
-    ));
-  }
-
-  /**
-   * Erzeugt den String, in dem die Koordinaten dargestellt werden. Unterklassen
-   * koennen diese Methode ueberschreiben, um die Darstellung zu aendern.
-   * Die uebergebenen Koordinaten sind bereits entsprechend der gesetzten
-   * Nachkommastellen gerundet!
-   * @param actCoord aktuelle Geoposition des Mauszeigers
-   * @param selStartCoord Geoposition des Selektion-Startpunkt (<code>null</code>
-   *        falls die aktuell kein Bereich selektiert wird)
-   */
-  protected String createGeoPositionString(final Point2D actCoord, final Point2D selStartCoord) {
-    String coordText = "";
-    // wenn die linke Maustaste gedrueckt ist (also ein Bereich
-    // selektiert wird), sind in selStartCoord die Startkoordinaten
-    // gespeichert
-    if ( selStartCoord != null )
-      coordText = "("+decForm.format(selStartCoord.getX())+" / "+decForm.format(selStartCoord.getY())+") - ";
-    coordText = coordText + "("+decForm.format(actCoord.getX())+" / "+decForm.format(actCoord.getY())+")";
-
-    return coordText;
-  }
-
-  /**
-   * Setzt die Anzahl an Nachkommastellen, die fuer die Koordinaten
-   * dargestellt werden
-   * @param fracDigits Anzahl an Nachkommastellen
-   */
-  public void setFractionDigits(final int fracDigits) {
-    this.fracFactor = Math.pow(10.0,fracDigits);
-    this.decForm.setMinimumFractionDigits(fracDigits);
-    this.decForm.setMaximumFractionDigits(fracDigits);
-  }
-
-  /**
-   * Liefert die Anzahl an Nachkommastellen, die fuer die Koordinaten
-   * dargestellt werden
-   */
-  public int getFractionDigits() {
-    return (int)Math.log10(this.fracFactor);
-  }
-
-  /**
-   * Wird aufgerufen, wenn der Maus-Button gedrueckt wird.
-   * Handelt es sich bei dem Event um ein {@link GeoMouseEvent} oder das Event
-   * von einem {@link JMapPane} ausgeloest wurde, werden die
-   * aktuellen Koordinaten in {@link #selStartCoord} gespeichert.
-   */
-  public void mousePressed(final MouseEvent e) {
-    final Point2D p = JMapPane.getMapCoordinatesFromEvent(e);
-    if ( p != null && e.getButton() == MouseEvent.BUTTON1) {
+
+/**
+ * Diese Klasse stellt ein {@link JLabel} dar, in dem (2dimensionale) Geo-Koordinaten
+ * angezeigt werden. Dabei werden die Koordinaten auf eine bestimmte Anzahl
+ * an Nachkommastellen gerundet.<br>
+ * Die Klasse fungiert als {@link MouseListener} und {@link MouseMotionListener} und
+ * kann so direkt an ein {@link JMapPane} gekoppelt werden. Die Koordinaten-Darstellung
+ * im Label aktualisiert sich somit automatisch, sobald sich die Maus ueber die
+ * Karte bewegt. Wird ein Kartenbereich selektiert (gedrueckte linke Maustaste),
+ * werden neben der aktuellen Position auch die Koordinaten des Selektionsstart
+ * angezeigt.<br>
+ * <b>Bemerke:</b><br>
+ * Eine Instanz des <code>GeoPositionLabel</code> muss dem {@link JMapPane} sowohl
+ * als {@linkplain JMapPane#addMouseListener(MouseListener) MouseListener}, als
+ * auch als {@linkplain JMapPane#addMouseMotionListener(MouseMotionListener) MouseMotionListener}
+ * hinzugefuegt werden. Ansonsten bekommt es nicht alle notwendigen Informationen
+ * mit!
+ * @see #setFractionDigits(int)
+ * @see #getFractionDigits()
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class GeoPositionLabel extends JLabel implements MouseInputListener {
+
+  // Faktor mit dem die Koordinaten vor dem Runden multipliziert und nach
+  // dem Runden dividiert werden
+  // --> bestimmt die dargestellten Nachkommastellen
+  private double fracFactor = 0.0;
+
+  /** Speichert das Format fuer die dargstellten Koordinaten */
+  protected final DecimalFormat decForm = new DecimalFormat();
+
+  /** Speichert die Koordinaten, die in dem Moment aktuell sind, wenn die linke
+   *  Maustaste gedruckt wird. Und zwar solange, bis die Taste wieder losgelassen
+   *  wird. Danach wieder <code>null</code>. */
+  protected Point2D selStartCoord = null;
+
+  /**
+   * Erzeugt ein neues Label. Die Koordinaten werden ohne Nachkommastellen
+   * dargestellt.
+   */
+  public GeoPositionLabel() {
+    this(0);
+  }
+
+  /**
+   * Erzeugt ein neues Label.
+   * @param fracDigits Anzahl an Nachkommastellen, auf die die Koordinaten gerundet
+   *                   werden
+   */
+  public GeoPositionLabel(final int fracDigits) {
+    super(" ");
+    // eine Stelle vor dem Komma soll immer dargestellt werden
+    this.decForm.setMinimumIntegerDigits(1);
+    // Nachkommastellen setzen
+    this.setFractionDigits(fracDigits);
+  }
+
+  /**
+   * Stellt die Koordinaten im Label dar, wenn es sich bei dem Event um
+   * ein {@link GeoMouseEvent} handelt  oder das Event von einem {@link JMapPane}
+   * ausgeloest wurde.<br>
+   * Wird von {@link #mousePressed(MouseEvent)}, {@link #mouseMoved(MouseEvent)}
+   * und {@link #mouseDragged(MouseEvent)} aufgerufen.
+   * @see #createGeoPositionString(Point2D,Point2D)
+   */
+  protected void displayCoordinates(final MouseEvent e) {
+    if ( e==null || !(e instanceof GeoMouseEvent) && !(e.getSource() instanceof JMapPane) )
+      return;
+
+    // aktuelle Geo-Position ermitteln und runden
+    final Point2D actCoord = JMapPane.getMapCoordinatesFromEvent(e);
+    if ( actCoord == null )
+      return;
+    final double actLat = Math.round(actCoord.getX() * fracFactor) / fracFactor;
+    final double actLon = Math.round(actCoord.getY() * fracFactor) / fracFactor;
+    // Position des Selektion-Startpunkts runden
+    double startLat = 0.0;
+    double startLon = 0.0;
+    if (selStartCoord != null) {
+      startLat = Math.round(selStartCoord.getX() * fracFactor) / fracFactor;
+      startLon = Math.round(selStartCoord.getY() * fracFactor) / fracFactor;
+    }
+    // Label setzen
+    setText(createGeoPositionString(
+        new Point2D.Double(actLat, actLon),
+        selStartCoord == null ? null : new Point2D.Double(startLat, startLon)
+    ));
+  }
+
+  /**
+   * Erzeugt den String, in dem die Koordinaten dargestellt werden. Unterklassen
+   * koennen diese Methode ueberschreiben, um die Darstellung zu aendern.
+   * Die uebergebenen Koordinaten sind bereits entsprechend der gesetzten
+   * Nachkommastellen gerundet!
+   * @param actCoord aktuelle Geoposition des Mauszeigers
+   * @param selStartCoord Geoposition des Selektion-Startpunkt (<code>null</code>
+   *        falls die aktuell kein Bereich selektiert wird)
+   */
+  protected String createGeoPositionString(final Point2D actCoord, final Point2D selStartCoord) {
+    String coordText = "";
+    // wenn die linke Maustaste gedrueckt ist (also ein Bereich
+    // selektiert wird), sind in selStartCoord die Startkoordinaten
+    // gespeichert
+    if ( selStartCoord != null )
+      coordText = "("+decForm.format(selStartCoord.getX())+" / "+decForm.format(selStartCoord.getY())+") - ";
+    coordText = coordText + "("+decForm.format(actCoord.getX())+" / "+decForm.format(actCoord.getY())+")";
+
+    return coordText;
+  }
+
+  /**
+   * Setzt die Anzahl an Nachkommastellen, die fuer die Koordinaten
+   * dargestellt werden
+   * @param fracDigits Anzahl an Nachkommastellen
+   */
+  public void setFractionDigits(final int fracDigits) {
+    this.fracFactor = Math.pow(10.0,fracDigits);
+    this.decForm.setMinimumFractionDigits(fracDigits);
+    this.decForm.setMaximumFractionDigits(fracDigits);
+  }
+
+  /**
+   * Liefert die Anzahl an Nachkommastellen, die fuer die Koordinaten
+   * dargestellt werden
+   */
+  public int getFractionDigits() {
+    return (int)Math.log10(this.fracFactor);
+  }
+
+  /**
+   * Wird aufgerufen, wenn der Maus-Button gedrueckt wird.
+   * Handelt es sich bei dem Event um ein {@link GeoMouseEvent} oder das Event
+   * von einem {@link JMapPane} ausgeloest wurde, werden die
+   * aktuellen Koordinaten in {@link #selStartCoord} gespeichert.
+   */
+  public void mousePressed(final MouseEvent e) {
+    final Point2D p = JMapPane.getMapCoordinatesFromEvent(e);
+    if ( p != null && e.getButton() == MouseEvent.BUTTON1) {
       selStartCoord = p;
       //MS: on simple click the Envelope-Coordinates should not
-      //    be shown!
-      //displayCoordinates(e);
-    }
-  }
-
-  /**
-   * Wird aufgerufen, wenn der Maus-Button wieder losgelassen wird.
-   * Setzt {@link #selStartCoord} auf <code>null</code>.
-   */
-  public void mouseReleased(final MouseEvent e) {
-    selStartCoord = null;
-  }
-
-  /**
-   * Macht nichts.
-   */
-  public void mouseClicked(final MouseEvent e) {
-  }
-
-  /**
-   * Wird aufgerufen, sobald die Maus bewegt wird.
-   * Stellt die Koordinaten im Label dar, wenn es sich bei dem Event um ein
-   * {@link GeoMouseEvent} handelt oder das Event von einem {@link JMapPane}
-   * ausgeloest wurde.
-   */
-  public void mouseMoved(final MouseEvent e) {
-    displayCoordinates(e);
-  }
-
-  /**
-   * Wird aufgerufen, sobald die Maus bei gedrueckter Taste bewegt wird.
-   * Stellt die Koordinaten im Label dar, wenn es sich bei dem Event um ein
-   * {@link GeoMouseEvent} handelt oder das Event von einem {@link JMapPane}
-   * ausgeloest wurde.
-   */
-  public void mouseDragged(final MouseEvent e) {
-    displayCoordinates(e);
-  }
-
-  /**
-   * Macht nichts.
-   */
-  public void mouseEntered(final MouseEvent e) {
-  }
-
-  /**
-   * Macht nichts.
-   */
-  public void mouseExited(final MouseEvent e) {
-  }
-}
+      //    be shown!
+      //displayCoordinates(e);
+    }
+  }
+
+  /**
+   * Wird aufgerufen, wenn der Maus-Button wieder losgelassen wird.
+   * Setzt {@link #selStartCoord} auf <code>null</code>.
+   */
+  public void mouseReleased(final MouseEvent e) {
+    selStartCoord = null;
+  }
+
+  /**
+   * Macht nichts.
+   */
+  public void mouseClicked(final MouseEvent e) {
+  }
+
+  /**
+   * Wird aufgerufen, sobald die Maus bewegt wird.
+   * Stellt die Koordinaten im Label dar, wenn es sich bei dem Event um ein
+   * {@link GeoMouseEvent} handelt oder das Event von einem {@link JMapPane}
+   * ausgeloest wurde.
+   */
+  public void mouseMoved(final MouseEvent e) {
+    displayCoordinates(e);
+  }
+
+  /**
+   * Wird aufgerufen, sobald die Maus bei gedrueckter Taste bewegt wird.
+   * Stellt die Koordinaten im Label dar, wenn es sich bei dem Event um ein
+   * {@link GeoMouseEvent} handelt oder das Event von einem {@link JMapPane}
+   * ausgeloest wurde.
+   */
+  public void mouseDragged(final MouseEvent e) {
+    displayCoordinates(e);
+  }
+
+  /**
+   * Macht nichts.
+   */
+  public void mouseEntered(final MouseEvent e) {
+  }
+
+  /**
+   * Macht nichts.
+   */
+  public void mouseExited(final MouseEvent e) {
+  }
+}

Modified: trunk/src/schmitzm/geotools/gui/GeotoolsGUIUtil.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/GeotoolsGUIUtil.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/GeotoolsGUIUtil.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,241 +1,270 @@
-package schmitzm.geotools.gui;
-
-import java.awt.Component;
-import java.io.File;
-import java.net.URL;
-import java.util.Locale;
-
-import javax.swing.JFileChooser;
-import javax.swing.JOptionPane;
-import javax.swing.filechooser.FileFilter;
-import javax.swing.filechooser.FileNameExtensionFilter;
-
-import org.apache.log4j.Logger;
-import org.geotools.coverage.grid.GridCoverage2D;
-import org.geotools.feature.FeatureCollection;
-
-import schmitzm.geotools.io.GeoExportUtil;
-import schmitzm.io.IOUtil;
-import schmitzm.lang.LangUtil;
-import schmitzm.lang.ResourceProvider;
-import schmitzm.swing.ExceptionDialog;
-import schmitzm.swing.SwingUtil;
-
-/**
- * Diese Klasse enthaelt statische Hilfsmethoden im Bereich Geotools GUI.
- * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class GeotoolsGUIUtil {
-  private static Logger LOGGER = Logger.getLogger( GeotoolsGUIUtil.class.getName() );
-
-  /** {@link ResourceProvider}, der die Lokalisation fuer GUI-Komponenten
-   *  des Package {@code schmitzm.geotools.gui} zur Verfuegung stellt. Diese sind
-   *  in properties-Datein unter {@code schmitzm.geotools.gui.resource.locales}
-   *  hinterlegt. */
-  public static ResourceProvider RESOURCE = new ResourceProvider( LangUtil.extendPackagePath(GeotoolsGUIUtil.class,"resource.locales.GTResourceBundle"), Locale.ENGLISH );
-
-	/**
-	 * Convenience method to access the translations in the {@link ResourceProvider}
-	 * resources.
-	 * 
-	 * @param key
-	 *            the key for the properties file
-	 * @param values
-	 *            optional values
-	 */
-	public static String R(String key, Object... values) {
-		return RESOURCE.getString(key, values);
-	}
-
-  
-  /** {@link FileNameExtensionFilter} fuer ArcInfoAscii-Raster. */
-  public static final FileNameExtensionFilter FILTER_RASTER_ASCII = new FileNameExtensionFilter("ASCII-Raster (*.asc)","asc");
-  /** {@link FileNameExtensionFilter} fuer GeoTiff-Raster. */
-  public static final FileNameExtensionFilter FILTER_RASTER_GEOTIFF = new FileNameExtensionFilter("GeoTiff (*.tif)","tif");
-  /** {@link FileNameExtensionFilter} fuer Shape-Files. */
-  public static final FileNameExtensionFilter FILTER_FEATURE_SHAPE = new FileNameExtensionFilter("Shape-File (*.shp)","shp");
-  
-  /**
-   * Zeigt einen Dialog zum Auswaehlen einer Datei an.
-   * @param parent dem Dialog uebergeordnete GUI-Komponente
-   * @param dialogType {@code JFileChooser.SAVE_DIALOG} oder {@code JFileChooser.OPEN_DIALOG}
-   * @param title Titel, der im Dialog angezeigt wird (kann {@code null} sein)
-   * @param initialDir Verzeichnis, das angezeigt wird (kann {@code null} sein)
-   * @param filter (optionale) Filter, die im Dialog angewaehlt werden koennen
-   * @return den FileChooser, in dem die Datei ausgewaehlt ist oder {@code null}
-   *         falls der Dialog abgebrochen wurde
-   */
-  private static JFileChooser chooseFile(Component parent, int dialogType, String title, File initialDir, FileFilter... filter) {
-    final JFileChooser fileChooser = new JFileChooser(initialDir);
-    fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
-    fileChooser.setMultiSelectionEnabled( false );
-    for (FileFilter f : filter)
-      fileChooser.addChoosableFileFilter(f);
-    if ( filter.length > 0 ) {
-      fileChooser.setFileFilter(filter[0]);
-      fileChooser.setAcceptAllFileFilterUsed(false);
-    }
-    if ( title != null )
-      fileChooser.setDialogTitle(title);
-    int retValue = 0;
-    if ( dialogType == JFileChooser.SAVE_DIALOG )
-      retValue = fileChooser.showSaveDialog(parent);
-    else if ( dialogType == JFileChooser.OPEN_DIALOG )
-      retValue = fileChooser.showOpenDialog(parent);
-    else
-      throw new IllegalArgumentException("Unsupported dialog type: "+dialogType);
-
-    if ( retValue != JFileChooser.APPROVE_OPTION )
-      return null;
-
-    return fileChooser;
-  }
-
-  /**
-   * Zeigt einen Dialog zum Auswaehlen einer Export-Datei an. Die
-   * Datei-Erweiterung wird entsprechend des ausgewaehlten Filters
-   * automatisch angehaengt. Existiert die Datei bereits, wird zum Bestaetigen#
-   * des Ueberschreibens aufgefordert.
-   * @param parent dem Dialog uebergeordnete GUI-Komponente
-   * @param dialogType {@code JFileChooser.SAVE_DIALOG} oder {@code JFileChooser.OPEN_DIALOG}
-   * @param title Titel, der im Dialog angezeigt wird (kann {@code null} sein)
-   * @param initialDir Verzeichnis, das angezeigt wird (kann {@code null} sein)
-   * @param filter (optionale) Filter, die im Dialog angewaehlt werden koennen
-   * @return den FileChooser, in dem die Datei ausgewaehlt ist oder {@code null}
-   *         falls der Dialog abgebrochen wurde
-   */
-  private static JFileChooser chooseExportFile(Component parent, String title, File initialDir, FileNameExtensionFilter... filter) {
-    JFileChooser expFileChooser = null;
-    do {
-      // Export-Datei auswaehlen
-      expFileChooser = chooseFile(
-        parent,
-        JFileChooser.SAVE_DIALOG,
-        title,
-        initialDir,
-        filter
-      );
-      if ( expFileChooser == null )
-        return null;
-      // Verzeichnis merken
-      initialDir = expFileChooser.getCurrentDirectory();
-
-      // Ueberschreiben bestaetigen
-      File   expFile    = expFileChooser.getSelectedFile();
-      String expFileExt = ((FileNameExtensionFilter)expFileChooser.getFileFilter()).getExtensions()[0];
-      expFile = IOUtil.appendFileExt(expFile, expFileExt);
-      expFileChooser.setSelectedFile(expFile);
-
-      if ( !expFile.exists() || approveFileOverwrite(parent,expFile.getName()) )
-        break;
-    } while ( true );
-
-    return expFileChooser;
-
-  }
-  /**
-   * Zeigt einen Dialog an, in dem das Ueberschreiben einer Datei bestaetigt
-   * werden muss.
-   * @param parent Uebergeordnete GUI-Komponente fuer die Meldung
-   * @param filename Bezeichnung der Datei
-   * @return {@code true}, falls das Ueberschreiben mit OK bestaetigt wurde
-   */
-  public static boolean approveFileOverwrite(Component parent, String filename) {
-    int retValue = JOptionPane.showConfirmDialog(
-      parent,
-      filename,
-      SwingUtil.RESOURCE.getString("Overwrite"),
-      JOptionPane.OK_CANCEL_OPTION,
-      JOptionPane.QUESTION_MESSAGE
-    );
-    return retValue == JOptionPane.OK_OPTION;
-  }
-
-  /**
-   * Exportiert eine {@link FeatureCollection} in ein Shape-File. Dabei
-   * wird ein Anwender-Dialog geoeffnet, um die Ziel-Datei auszuwaehlen.
-   * Tritt ein Fehler beim Export auf, wird dieser in einem Dialog angezeigt.
-   * @param parent dem Dialog uebergeordnete GUI-Komponente (kann {@code null} sein)
-   * @param fc zu exportierende {@link FeatureCollection}
-   * @param desc Beschreibung der FeatureCollection, die im Dialog-Titel angezeigt
-   *             wird (kann {@code null} sein)
-   * @return die Export-Datei, oder {@code null} falls der Export abgebrochen
-   *         oder aufgrund eines Fehlers nicht durchgefuehrt wurde
-   */
-  public static URL exportFeatureCollection(Component parent, FeatureCollection fc, String desc) {
-    String title = RESOURCE.getString("schmitzm.geotools.gui.GeotoolsGUIUtil.SaveFeature");
-    if ( desc != null && !desc.trim().equals("") )
-      title += " [" + desc.trim() + "]";
-
-    // Export-Datei auswaehlen
-    JFileChooser destFileChooser = chooseExportFile(
-      parent,
-      title,
-      null,
-      FILTER_FEATURE_SHAPE
-    );
-    if ( destFileChooser == null )
-      return null;
-    File destFile = destFileChooser.getSelectedFile();
-
-    // FeatureCollection exportieren, je nach angewaehltem Format
-    try {
-      FileFilter fileFilter = destFileChooser.getFileFilter();
-      if ( fileFilter == FILTER_FEATURE_SHAPE )
-        GeoExportUtil.writeFeaturesToShapeFile(fc, destFile);
-      else
-        throw new UnsupportedOperationException("Chosen file format not supported: "+fileFilter.getDescription());
-      return destFile.toURI().toURL();
-    } catch (Exception err) {
-      ExceptionDialog.show(parent,err);
-      return null;
-    }
-  }
-
-  /**
-   * Exportiert ein {@link GridCoverage2D} in eine Raster-Datei. Dabei
-   * wird ein Anwender-Dialog geoeffnet, um die Ziel-Datei und den Datei-Typ
-   * auszuwaehlen.
-   * Tritt ein Fehler beim Export auf, wird dieser in einem Dialog angezeigt.
-   * @param parent dem Dialog uebergeordnete GUI-Komponente (kann {@code null} sein)
-   * @param gc zu exportierendes Raster
-   * @param desc Beschreibung des Rasters, die im Dialog-Titel angezeigt
-   *             wird (kann {@code null} sein)
-   * @return die Export-Datei, oder {@code null} falls der Export abgebrochen
-   *         oder aufgrund eines Fehlers nicht durchgefuehrt wurde
-   */
-  public static URL exportGridCoverage2D(Component parent, GridCoverage2D gc, String desc) {
-    String title = RESOURCE.getString("schmitzm.geotools.gui.GeotoolsGUIUtil.SaveRaster");
-    if ( desc != null && !desc.trim().equals("") )
-      title += " [" + desc.trim() + "]";
-    
-    // Export-Datei auswaehlen
-    JFileChooser destFileChooser = chooseExportFile(
-      parent,
-      title,
-      null,
-      FILTER_RASTER_ASCII,
-      FILTER_RASTER_GEOTIFF
-    );
-    if ( destFileChooser == null )
-      return null;
-    File destFile = destFileChooser.getSelectedFile();
-
-    // Raster exportieren, je nach angewaehltem Format
-    try {
-      FileFilter fileFilter = destFileChooser.getFileFilter();
-      if ( fileFilter == FILTER_RASTER_ASCII )
-        GeoExportUtil.writeGridToArcInfoASCII(gc, destFile);
-      else if ( fileFilter == FILTER_RASTER_GEOTIFF )
-        GeoExportUtil.writeGridToGeoTiff(gc, destFile);
-      else
-        throw new UnsupportedOperationException("Chosen file format not supported: "+fileFilter.getDescription());
-      return destFile.toURI().toURL();
-    } catch (Exception err) {
-      ExceptionDialog.show(parent,err);
-      return null;
-    }
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.gui;
+
+import java.awt.Component;
+import java.io.File;
+import java.net.URL;
+import java.util.Locale;
+
+import javax.swing.JFileChooser;
+import javax.swing.JOptionPane;
+import javax.swing.filechooser.FileFilter;
+import javax.swing.filechooser.FileNameExtensionFilter;
+
+import org.apache.log4j.Logger;
+import org.geotools.coverage.grid.GridCoverage2D;
+import org.geotools.feature.FeatureCollection;
+
+import schmitzm.geotools.io.GeoExportUtil;
+import schmitzm.io.IOUtil;
+import schmitzm.lang.LangUtil;
+import schmitzm.lang.ResourceProvider;
+import schmitzm.swing.ExceptionDialog;
+import schmitzm.swing.SwingUtil;
+
+/**
+ * Diese Klasse enthaelt statische Hilfsmethoden im Bereich Geotools GUI.
+ * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class GeotoolsGUIUtil {
+  private static Logger LOGGER = Logger.getLogger( GeotoolsGUIUtil.class.getName() );
+
+  /** {@link ResourceProvider}, der die Lokalisation fuer GUI-Komponenten
+   *  des Package {@code schmitzm.geotools.gui} zur Verfuegung stellt. Diese sind
+   *  in properties-Datein unter {@code schmitzm.geotools.gui.resource.locales}
+   *  hinterlegt. */
+  public static ResourceProvider RESOURCE = new ResourceProvider( LangUtil.extendPackagePath(GeotoolsGUIUtil.class,"resource.locales.GTResourceBundle"), Locale.ENGLISH );
+
+	/**
+	 * Convenience method to access the translations in the {@link ResourceProvider}
+	 * resources.
+	 * 
+	 * @param key
+	 *            the key for the properties file
+	 * @param values
+	 *            optional values
+	 */
+	public static String R(String key, Object... values) {
+		return RESOURCE.getString(key, values);
+	}
+
+  
+  /** {@link FileNameExtensionFilter} fuer ArcInfoAscii-Raster. */
+  public static final FileNameExtensionFilter FILTER_RASTER_ASCII = new FileNameExtensionFilter("ASCII-Raster (*.asc)","asc");
+  /** {@link FileNameExtensionFilter} fuer GeoTiff-Raster. */
+  public static final FileNameExtensionFilter FILTER_RASTER_GEOTIFF = new FileNameExtensionFilter("GeoTiff (*.tif)","tif");
+  /** {@link FileNameExtensionFilter} fuer Shape-Files. */
+  public static final FileNameExtensionFilter FILTER_FEATURE_SHAPE = new FileNameExtensionFilter("Shape-File (*.shp)","shp");
+  
+  /**
+   * Zeigt einen Dialog zum Auswaehlen einer Datei an.
+   * @param parent dem Dialog uebergeordnete GUI-Komponente
+   * @param dialogType {@code JFileChooser.SAVE_DIALOG} oder {@code JFileChooser.OPEN_DIALOG}
+   * @param title Titel, der im Dialog angezeigt wird (kann {@code null} sein)
+   * @param initialDir Verzeichnis, das angezeigt wird (kann {@code null} sein)
+   * @param filter (optionale) Filter, die im Dialog angewaehlt werden koennen
+   * @return den FileChooser, in dem die Datei ausgewaehlt ist oder {@code null}
+   *         falls der Dialog abgebrochen wurde
+   */
+  private static JFileChooser chooseFile(Component parent, int dialogType, String title, File initialDir, FileFilter... filter) {
+    final JFileChooser fileChooser = new JFileChooser(initialDir);
+    fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
+    fileChooser.setMultiSelectionEnabled( false );
+    for (FileFilter f : filter)
+      fileChooser.addChoosableFileFilter(f);
+    if ( filter.length > 0 ) {
+      fileChooser.setFileFilter(filter[0]);
+      fileChooser.setAcceptAllFileFilterUsed(false);
+    }
+    if ( title != null )
+      fileChooser.setDialogTitle(title);
+    int retValue = 0;
+    if ( dialogType == JFileChooser.SAVE_DIALOG )
+      retValue = fileChooser.showSaveDialog(parent);
+    else if ( dialogType == JFileChooser.OPEN_DIALOG )
+      retValue = fileChooser.showOpenDialog(parent);
+    else
+      throw new IllegalArgumentException("Unsupported dialog type: "+dialogType);
+
+    if ( retValue != JFileChooser.APPROVE_OPTION )
+      return null;
+
+    return fileChooser;
+  }
+
+  /**
+   * Zeigt einen Dialog zum Auswaehlen einer Export-Datei an. Die
+   * Datei-Erweiterung wird entsprechend des ausgewaehlten Filters
+   * automatisch angehaengt. Existiert die Datei bereits, wird zum Bestaetigen#
+   * des Ueberschreibens aufgefordert.
+   * @param parent dem Dialog uebergeordnete GUI-Komponente
+   * @param dialogType {@code JFileChooser.SAVE_DIALOG} oder {@code JFileChooser.OPEN_DIALOG}
+   * @param title Titel, der im Dialog angezeigt wird (kann {@code null} sein)
+   * @param initialDir Verzeichnis, das angezeigt wird (kann {@code null} sein)
+   * @param filter (optionale) Filter, die im Dialog angewaehlt werden koennen
+   * @return den FileChooser, in dem die Datei ausgewaehlt ist oder {@code null}
+   *         falls der Dialog abgebrochen wurde
+   */
+  private static JFileChooser chooseExportFile(Component parent, String title, File initialDir, FileNameExtensionFilter... filter) {
+    JFileChooser expFileChooser = null;
+    do {
+      // Export-Datei auswaehlen
+      expFileChooser = chooseFile(
+        parent,
+        JFileChooser.SAVE_DIALOG,
+        title,
+        initialDir,
+        filter
+      );
+      if ( expFileChooser == null )
+        return null;
+      // Verzeichnis merken
+      initialDir = expFileChooser.getCurrentDirectory();
+
+      // Ueberschreiben bestaetigen
+      File   expFile    = expFileChooser.getSelectedFile();
+      String expFileExt = ((FileNameExtensionFilter)expFileChooser.getFileFilter()).getExtensions()[0];
+      expFile = IOUtil.appendFileExt(expFile, expFileExt);
+      expFileChooser.setSelectedFile(expFile);
+
+      if ( !expFile.exists() || approveFileOverwrite(parent,expFile.getName()) )
+        break;
+    } while ( true );
+
+    return expFileChooser;
+
+  }
+  /**
+   * Zeigt einen Dialog an, in dem das Ueberschreiben einer Datei bestaetigt
+   * werden muss.
+   * @param parent Uebergeordnete GUI-Komponente fuer die Meldung
+   * @param filename Bezeichnung der Datei
+   * @return {@code true}, falls das Ueberschreiben mit OK bestaetigt wurde
+   */
+  public static boolean approveFileOverwrite(Component parent, String filename) {
+    int retValue = JOptionPane.showConfirmDialog(
+      parent,
+      filename,
+      SwingUtil.RESOURCE.getString("Overwrite"),
+      JOptionPane.OK_CANCEL_OPTION,
+      JOptionPane.QUESTION_MESSAGE
+    );
+    return retValue == JOptionPane.OK_OPTION;
+  }
+
+  /**
+   * Exportiert eine {@link FeatureCollection} in ein Shape-File. Dabei
+   * wird ein Anwender-Dialog geoeffnet, um die Ziel-Datei auszuwaehlen.
+   * Tritt ein Fehler beim Export auf, wird dieser in einem Dialog angezeigt.
+   * @param parent dem Dialog uebergeordnete GUI-Komponente (kann {@code null} sein)
+   * @param fc zu exportierende {@link FeatureCollection}
+   * @param desc Beschreibung der FeatureCollection, die im Dialog-Titel angezeigt
+   *             wird (kann {@code null} sein)
+   * @return die Export-Datei, oder {@code null} falls der Export abgebrochen
+   *         oder aufgrund eines Fehlers nicht durchgefuehrt wurde
+   */
+  public static URL exportFeatureCollection(Component parent, FeatureCollection fc, String desc) {
+    String title = RESOURCE.getString("schmitzm.geotools.gui.GeotoolsGUIUtil.SaveFeature");
+    if ( desc != null && !desc.trim().equals("") )
+      title += " [" + desc.trim() + "]";
+
+    // Export-Datei auswaehlen
+    JFileChooser destFileChooser = chooseExportFile(
+      parent,
+      title,
+      null,
+      FILTER_FEATURE_SHAPE
+    );
+    if ( destFileChooser == null )
+      return null;
+    File destFile = destFileChooser.getSelectedFile();
+
+    // FeatureCollection exportieren, je nach angewaehltem Format
+    try {
+      FileFilter fileFilter = destFileChooser.getFileFilter();
+      if ( fileFilter == FILTER_FEATURE_SHAPE )
+        GeoExportUtil.writeFeaturesToShapeFile(fc, destFile);
+      else
+        throw new UnsupportedOperationException("Chosen file format not supported: "+fileFilter.getDescription());
+      return destFile.toURI().toURL();
+    } catch (Exception err) {
+      ExceptionDialog.show(parent,err);
+      return null;
+    }
+  }
+
+  /**
+   * Exportiert ein {@link GridCoverage2D} in eine Raster-Datei. Dabei
+   * wird ein Anwender-Dialog geoeffnet, um die Ziel-Datei und den Datei-Typ
+   * auszuwaehlen.
+   * Tritt ein Fehler beim Export auf, wird dieser in einem Dialog angezeigt.
+   * @param parent dem Dialog uebergeordnete GUI-Komponente (kann {@code null} sein)
+   * @param gc zu exportierendes Raster
+   * @param desc Beschreibung des Rasters, die im Dialog-Titel angezeigt
+   *             wird (kann {@code null} sein)
+   * @return die Export-Datei, oder {@code null} falls der Export abgebrochen
+   *         oder aufgrund eines Fehlers nicht durchgefuehrt wurde
+   */
+  public static URL exportGridCoverage2D(Component parent, GridCoverage2D gc, String desc) {
+    String title = RESOURCE.getString("schmitzm.geotools.gui.GeotoolsGUIUtil.SaveRaster");
+    if ( desc != null && !desc.trim().equals("") )
+      title += " [" + desc.trim() + "]";
+    
+    // Export-Datei auswaehlen
+    JFileChooser destFileChooser = chooseExportFile(
+      parent,
+      title,
+      null,
+      FILTER_RASTER_ASCII,
+      FILTER_RASTER_GEOTIFF
+    );
+    if ( destFileChooser == null )
+      return null;
+    File destFile = destFileChooser.getSelectedFile();
+
+    // Raster exportieren, je nach angewaehltem Format
+    try {
+      FileFilter fileFilter = destFileChooser.getFileFilter();
+      if ( fileFilter == FILTER_RASTER_ASCII )
+        GeoExportUtil.writeGridToArcInfoASCII(gc, destFile);
+      else if ( fileFilter == FILTER_RASTER_GEOTIFF )
+        GeoExportUtil.writeGridToGeoTiff(gc, destFile);
+      else
+        throw new UnsupportedOperationException("Chosen file format not supported: "+fileFilter.getDescription());
+      return destFile.toURI().toURL();
+    } catch (Exception err) {
+      ExceptionDialog.show(parent,err);
+      return null;
+    }
+  }
+
+}

Modified: trunk/src/schmitzm/geotools/gui/GridPanel.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/GridPanel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/GridPanel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,378 +1,396 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.gui;
-
-import java.awt.Color;
-import java.awt.Graphics;
-import java.awt.geom.AffineTransform;
-import java.text.DecimalFormat;
-
-import org.apache.log4j.Logger;
-import org.geotools.referencing.CRS;
-import org.geotools.referencing.operation.projection.PointOutsideEnvelopeException;
-import org.opengis.referencing.FactoryException;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-import org.opengis.referencing.operation.MathTransform;
-
-import schmitzm.lang.LangUtil;
-import schmitzm.lang.ResourceProvider;
-import schmitzm.swing.JPanel;
-import schmitzm.swing.SwingUtil;
-
-/**
- * Diese Klasse stellt eine horizontale oder vertikale Koordinaten-Leiste (Grid)
- * dar, die an ein {@link JMapPane} gekoppelt ist.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class GridPanel extends JPanel {
-  private final Logger LOGGER = LangUtil.createLogger(this);
-  private static final ResourceProvider RES = GeotoolsGUIUtil.RESOURCE;
-
-  private static final DecimalFormat numFormat = new DecimalFormat("###,###,##0");
-
-  /** Laenge der Grid-Abschnitts-Linien.  */
-  private static final int GRID_LINE_SIZE = 10;
-  /** Container-Breite bei vertikalem Grid. */
-  public static final int VERT_WIDTH     = 50;
-  /** Container-Hoehe bei horizontalem Grid. */
-  public static final int HOR_HEIGHT     = 20;
-
-  /** Flag fuer ein horizontales Grid. */
-  public static final int HORIZONTAL = 1;
-  /** Flag fuer ein vertikales Grid. */
-  public static final int VERTICAL = 2;
-
-  /** Speichert die Orientierung des Grid (Horizontal oder Vertikal). */
-  private int orientation = 0;
-
-  /** Karte, an der die Koordinaten-Leiste ausgerichtet wird. */
-  protected JMapPane mapPane = null;
-
-  /** Transformation von Karten-CRS zu CRS des Koordinaten-Rasters */
-  protected MathTransform mapToGrid = null;
-  /** Transformation von CRS des Koordinaten-Rasters zu Karten-CRS*/
-  protected MathTransform gridToMap = null;
-  /** Speichert das CRS, fuer das die Transformationen erstellt wurden. */
-  private CoordinateReferenceSystem transformedMapCRS = null;
-
-  /**
-   * Erzeugt eine Koordinaten-Leiste fuer ein {@link JMapPane}.
-   * @param orientation Orientierung ({@link #HORIZONTAL} oder {@link #VERTICAL})
-   * @param mapPane     Karte an der die Koordinaten-Leiste ausgerichtet wird
-   */
-  public GridPanel(int orientation, JMapPane mapPane) {
-    super();
-
-    this.orientation = orientation;
-    this.mapPane     = mapPane;
-    if ( isVertical() )
-      SwingUtil.setPreferredWidth(this,VERT_WIDTH);
-    else
-      SwingUtil.setPreferredHeight(this,HOR_HEIGHT);
-  }
-
-  /**
-   * Liefert die Orientierung der Koordinaten-Leiste.
-   * @see #HORIZONTAL
-   * @see #VERTICAL
-   */
-  public int getOrientation() {
-    return orientation;
-  }
-
-  /**
-   * Prueft, ob es sich um eine horizontale Koordinaten-Leiste handelt.
-   */
-  public boolean isHorizontal() {
-    return this.orientation == HORIZONTAL;
-  }
-
-  /**
-   * Prueft, ob es sich um eine vertikale Koordinaten-Leiste handelt.
-   */
-  public boolean isVertical() {
-    return this.orientation == VERTICAL;
-  }
-
-  /**
-   * Zeichnet die Koordinaten-Leiste.
-   * @param g Graphics
-   */
-  public void paint(Graphics g) {
-    super.paint(g);
-    if ( getParent() == null || mapPane.getMapArea() == null )
-      return;
-
-    CoordinateReferenceSystem mapCRS = null;   // (aktuelles) CRS des MapPane
-    CoordinateReferenceSystem gridCRS = null;  // CRS fuer die Grad/Min/Sek-Anzeige
-//    try {
-//      final CoordinateReferenceSystem UTM   = CRS.decode("EPSG:32631"); // utm zone 31n
-//      final CoordinateReferenceSystem WGS84 = CRS.decode("EPSG:4326"); // lat/lon (WGS84)
-////      final CoordinateReferenceSystem WGS84 = org.geotools.referencing.crs.DefaultGeographicCRS.WGS84;// lat/lon
-////      final CoordinateReferenceSystem NAD83 = CRS.decode("EPSG:100002"); // lat/lon
-////      mapCRS  = mapPane.getContext().getCoordinateReferenceSystem();
-//      mapCRS = UTM;
-//      gridCRS = WGS84;
-//    } catch (Exception err) {
-//      return;
-//    }
-
-
-    mapCRS  = mapPane.getContext().getCoordinateReferenceSystem();
-    gridCRS = org.geotools.referencing.crs.DefaultGeographicCRS.WGS84;// lat/lon
-//    LOGGER.debug("mapCRS: "+mapCRS);
-//    LOGGER.debug("gridCRS: "+gridCRS);
-
-    double     minX   = mapPane.getMapArea().getMinX();
-    double     minY   = mapPane.getMapArea().getMinY();
-    double     maxX   = mapPane.getMapArea().getMaxX();
-    double     maxY   = mapPane.getMapArea().getMaxY();
-
-// commented out, because it was unused
-//    double     width  = mapPane.getMapArea().getWidth();
-//    double     height = mapPane.getMapArea().getHeight();
-
-    // Minimum/Maximum des Grids in MapPane-CRS (MCRS)
-    double[] mapMin_MCRS = new double[] {minX,minY};
-    double[] mapMax_MCRS = isVertical() ? new double[] {minX,maxY} : new double[] {maxX,minY};
-    // Minimum/Maximum des Grids in Grid-CRS (GCRS)
-    double[] mapMin_GCRS = new double[2];
-    double[] mapMax_GCRS = new double[2];
-
-    try {
-      try {
-        // Der Effizienz halber, die Transformation nur neu ermitteln
-        // wenn sich das Karten-CRS geaendert hat
-        if ( mapToGrid == null || gridToMap == null || transformedMapCRS == null || !transformedMapCRS.equals(mapCRS) ) {
-          mapToGrid = CRS.findMathTransform(mapCRS, gridCRS);
-          gridToMap = CRS.findMathTransform(gridCRS, mapCRS);
-          // CRS merken, fuer das Transformation erstellt wurde
-          transformedMapCRS = mapCRS;
-        }
-      } catch (FactoryException  err) {
-        LOGGER.warn("CRS-Transformation to WGS84 failed: "+err.getMessage());
-        mapToGrid = CRS.findMathTransform(mapCRS, gridCRS, true);
-        gridToMap = CRS.findMathTransform(gridCRS, mapCRS, true);
-        LOGGER.warn("CRS-Transformation without datum shift");
-        // CRS merken, fuer das Transformation erstellt wurde
-        transformedMapCRS = mapCRS;
-      }
-      mapToGrid.transform( mapMin_MCRS, 0, mapMin_GCRS, 0, 1  );
-      mapToGrid.transform( mapMax_MCRS, 0, mapMax_GCRS, 0, 1  );
-    } catch (PointOutsideEnvelopeException err) {
-      return;
-    } catch (Exception err) {
-      LOGGER.error("CRS-Transformation to WGS84 failed: "+err.getMessage());
-      LOGGER.debug("CRS-Transformation to WGS84 failed: "+err.getMessage(),err);
-    }
-
-//   // Ergebnis von Transform: {Latitude,Longitude}
-//   int idx = isVertical() ? 0 : 1;
-   // SEHR SEHR MERKWUERDIG: Mal liefert Transform {Latitude,Longitude}, und
-   //                        manchmal {Longitude,Latitude}!!
-   // WORKAROUND (klappt natuerlich nicht mit allen CRS!):
-   //       Wenn  X_MCRS > Y_MCRS, dann muss auch X_GCRS > Y_GCRS
-  int idx = determineCompatibleArrayIndex(mapMin_MCRS,mapMin_GCRS,mapMax_MCRS,mapMax_GCRS);
-//   LOGGER.debug( isVertical() ? "V" : "H" );
-//   LOGGER.debug( "Min MCRS: "+mapMin_MCRS[0]+", "+mapMin_MCRS[1]+"         GCRS:"+mapMin_GCRS[0]+", "+mapMin_GCRS[1]);
-//   LOGGER.debug( "Max MCRS: "+mapMax_MCRS[0]+", "+mapMax_MCRS[1]+"         GCRS:"+mapMax_GCRS[0]+", "+mapMax_GCRS[1]);
-//   LOGGER.debug( "  --> "+idx+"\n");
-
-   double mapMin = mapMin_GCRS[idx];
-   double mapMax = mapMax_GCRS[idx];
-   // Maximale Groesse des Grid in Pixel
-   int maxSize = isHorizontal() ? getParent().getWidth() : getParent().getHeight();
-
-   // Passende Grid-Unterteilung in Grad
-   double gridDist = determineGridDistance(mapMin,mapMax,maxSize);
-   // Leiste zeichnen
-   if ( isHorizontal() )
-     g.drawLine(0,0,maxSize,0);
-   else
-     g.drawLine(VERT_WIDTH-1,0,VERT_WIDTH-1,maxSize);
-
-   // Abschnitte zeichnen
-   double   firstGrid = Math.ceil(mapMin/gridDist)*gridDist; // 1. Abschnitt in Lat bzw. Lon
-   double[] grid_GCRS = mapMin_GCRS.clone(); // Ausgangspunkt
-   double[] grid_MCRS = new double[2];
-   AffineTransform mapToWin = mapPane.getTransform();
-   for (double gridPos=firstGrid; gridPos<=mapMax; gridPos+=gridDist) {
-     grid_GCRS[idx] = gridPos;
-     // In Map-CRS und dann in Fenster-Koordinaten transformieren
-     double[] grid_WINDOW = new double[2];
-     try {
-       gridToMap.transform(grid_GCRS, 0, grid_MCRS, 0, 1);
-       mapToWin.inverseTransform(grid_MCRS,0,grid_WINDOW,0,1);
-//     } catch (Exception err) {
-     } catch (Throwable err) {
-       LOGGER.warn("Error ignored during paint of coordinate grid: "+err);
-       continue;
-     }
-     // Grid-Abschnitt zeichnen
-     int x1 = isVertical() ? VERT_WIDTH-GRID_LINE_SIZE : (int)grid_WINDOW[0];
-     int y1 = isVertical() ? (int)grid_WINDOW[1] : 0;
-     int x2 = isVertical() ? x1+GRID_LINE_SIZE : x1;
-     int y2 = isVertical() ? y1 : y1+GRID_LINE_SIZE;
-     g.drawLine(x1,y1,x2,y2);
-
-     // Koordinate anzeigen
-     double coord = grid_GCRS[idx];
-     int degrees = (int)coord;
-     int minutes = (int)Math.round((coord-degrees)*60 );
-     // Aufgrund des Minuten-Systems kann schlecht im Vorhinein gerundet
-     // werden. Deshalb wird im Nachhinein ein etwaiger Rundungsfehler
-     // ausgeglichen
-     if ( Math.abs(minutes) >= 60 ) {
-       degrees += Math.signum(minutes);
-       minutes -= Math.signum(minutes) * 60;
-     }
-     String coordStr = Math.abs(degrees)+"°"+Math.abs(minutes);
-     if ( degrees != 0 || minutes != 0 ) {
-       if (isVertical())
-         coordStr += RES.getString( (coord < 0) ? "schmitzm.geotools.gui.GeotoolsGUIUtil.SOUTH.Abb" : "schmitzm.geotools.gui.GeotoolsGUIUtil.NORTH.Abb" );
-       else
-         coordStr += RES.getString( (coord < 0) ? "schmitzm.geotools.gui.GeotoolsGUIUtil.WEST.Abb" : "schmitzm.geotools.gui.GeotoolsGUIUtil.EAST.Abb" );
-     }
-     x1 = isVertical() ?    5 : x1 + 5;
-     y1 = isVertical() ? y1-2 : y1 + 12;
-     g.drawString( coordStr, x1, y1 );
-   }
-
-/////////////   Test und Debugging /////////////////
-//    System.out.println("2 UTM lat="+minY+" lon="+minX+"       --> Degree lat="+dest2[0]+" lon="+dest2[1]);
-
-//    org.geotools.referencing.operation.DefaultMathTransformFactory.main(new String[] {});
-//    if ( debug == 0) {
-//      schmitzm.lang.WorkingThread w = new schmitzm.lang.WorkingThread() {
-//        java.util.Set codes = null;
-//        public void performInit() {
-//          codes = CRS.getSupportedCodes("EPSG");
-//        }
-//        public void performWork() {
-//          for (Object code : codes) {
-//            String crsCode = ((String)code).startsWith("EPSG") ? (String)code : "EPSG:"+((String)code);
-//            try {
-//              CoordinateReferenceSystem crs = CRS.decode(crsCode);
-//              System.out.println(code+"\t"+crsCode+"\t"+crs.getName());
-//            } catch (Exception e) {
-//              System.out.println(code+"\t"+crsCode+"\tError");
-//              break;
-//            }
-//          }
-//        }
-//        public void performDispose() {
-//        }
-//      };
-//      debug = 1;
-//      w.start();
-//    }
-  }
-
-  /**
-   * Bestimmt eine "passende" Unterteilung fuer das Grid.
-   */
-  private static double determineGridDistance(double mapMin_LL, double mapMax_LL, int panelSize) {
-    // Differenz zwischen Min/Max-Koordinaten = darzustellender Bereich in Grad
-    double diff = Math.abs( mapMin_LL - mapMax_LL );
-    // Distanz zwischen zwei Unterteilungen in Grad
-    double dist = 0.0;
-    if ( diff < 10/60.0 )      // < 10 Min. -->  1 Min.-Aufteilung
-      dist = 1/60.0;
-    else if ( diff < 30/60.0 ) // < 30 Min. -->  5 Min.-Aufteilung
-      dist = 5/60.0;
-    else if ( diff <  1 )      // <  1?     --> 10 Min.-Aufteilung
-      dist = 10/60.0;
-    else if ( diff <  3 )      // <  3?     --> 15 Min.-Aufteilung
-      dist = 15/60.0;
-    else if ( diff <  5 )      // <  5?     --> 30 Min.-Aufteilung
-      dist = 30/60.0;
-    else if ( diff < 11 )      // < 11?     -->  1?-Aufteilung
-      dist = 1;
-    else                       // sonst     -->  2?-Aufteilung
-      dist = 2;
-
-    // Solange der Abstand zwischen 2 Unterteilungen weniger als 40 Pixel
-    // betraegt --> Unterteilung verdoppeln
-    while ( diff != 0 && dist != 0 && panelSize / (diff / dist) < 40 )
-      dist *=2;
-
-    return dist;
-  }
-
-//  /**
-//   * Diese Methode stellt einen Workaround fuer einen sehr sehr merkwuerdigen
-//   * {@link MathTransform}-Effekt dar. Mal liefert Transform die Koordinaten
-//   * als {Latitude,Longitude}-Array, und manchmal als {Longitude,Latitude}!
-//   * Diese Methode versucht zu ermitteln, in welchem Array-Index die
-//   * benoetigte Koordinate (je nachdem ob es sich um ein horizontales oder
-//   * vertikales Grid handelt) tatsaechlich befindet.
-//   * @param coord_SCRS Koordinate (in Quell-CRS)
-//   * @param coord_DCRS transformierte Koordinate (in Ziel-CRS)
-//   */
-//  private int determineCompatibleArrayIndex(double[] coord_SCRS, double[] coord_DCRS) {
-//    // SEHR SEHR MERKWUERDIG: Mal liefert Transform {Latitude,Longitude}, und
-//    //                        manchmal {Longitude,Latitude}!!
-//    // WORKAROUND (klappt natuerlich nicht mit allen CRS!):
-//    //       Wenn  X_sourceCRS > Y_sourceCRS, dann muss auch X_destCRS > Y_destCRS
-//    int idx = 0;
-//    if (coord_SCRS[0] > coord_SCRS[1] && coord_DCRS[0] > coord_DCRS[1] ||
-//        coord_SCRS[0] < coord_SCRS[1] && coord_DCRS[0] < coord_DCRS[1] ||
-//        coord_SCRS[0] == coord_SCRS[1] && coord_DCRS[0] == coord_DCRS[1])
-//      idx = isHorizontal() ? 0 : 1;
-//    else
-//      idx = isHorizontal() ? 1 : 0;
-//    return idx;
-//  }
-
-  /**
-   * Diese Methode stellt einen Workaround fuer einen sehr sehr merkwuerdigen
-   * {@link MathTransform}-Effekt dar. Mal liefert Transform die Koordinaten
-   * als {Latitude,Longitude}-Array, und manchmal als {Longitude,Latitude}!
-   * Diese Methode versucht zu ermitteln, in welchem Array-Index die
-   * benoetigte Koordinate (je nachdem ob es sich um ein horizontales oder
-   * vertikales Grid handelt) tatsaechlich befindet.
-   */
-  private int determineCompatibleArrayIndex(double[] mapMin_MCRS, double[] mapMin_GCRS,double[] mapMax_MCRS, double[] mapMax_GCRS) {
-    // SEHR SEHR MERKWUERDIG: Mal liefert Transform {Latitude,Longitude}, und
-    //                        manchmal {Longitude,Latitude}!!
-    // WORKAROUND (klappt natuerlich nicht mit allen CRS!):
-    //       Wenn  X_sourceCRS > Y_sourceCRS, dann muss auch X_destCRS > Y_destCRS
-
-
-    double diff0_GCRS = mapMax_GCRS[0] - mapMin_GCRS[0];
-    double diff1_GCRS = mapMax_GCRS[1] - mapMin_GCRS[1];
-
-    return diff0_GCRS > diff1_GCRS ? 0 : 1;
-  }
-  
-  /**
-   * Nuetzlich wenn die Componente gedruckt (z.B. wenn ein Screenshot gemacht wird) wird. Dann werden wird der
-   * Hintergrund auf WEISS gesetzt.
-   *
-   * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-   *         Kr&uuml;ger</a>
-   */
-  @Override
-  public void print(Graphics g) {
-      Color orig = getBackground();
-      setBackground(Color.WHITE);
-
-      // wrap in try/finally so that we always restore the state
-      try {
-          super.print(g);
-      } finally {
-          setBackground(orig);
-      }
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.gui;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.geom.AffineTransform;
+import java.text.DecimalFormat;
+
+import org.apache.log4j.Logger;
+import org.geotools.referencing.CRS;
+import org.geotools.referencing.operation.projection.PointOutsideEnvelopeException;
+import org.opengis.referencing.FactoryException;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.referencing.operation.MathTransform;
+
+import schmitzm.lang.LangUtil;
+import schmitzm.lang.ResourceProvider;
+import schmitzm.swing.JPanel;
+import schmitzm.swing.SwingUtil;
+
+/**
+ * Diese Klasse stellt eine horizontale oder vertikale Koordinaten-Leiste (Grid)
+ * dar, die an ein {@link JMapPane} gekoppelt ist.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class GridPanel extends JPanel {
+  private final Logger LOGGER = LangUtil.createLogger(this);
+  private static final ResourceProvider RES = GeotoolsGUIUtil.RESOURCE;
+
+  private static final DecimalFormat numFormat = new DecimalFormat("###,###,##0");
+
+  /** Laenge der Grid-Abschnitts-Linien.  */
+  private static final int GRID_LINE_SIZE = 10;
+  /** Container-Breite bei vertikalem Grid. */
+  public static final int VERT_WIDTH     = 50;
+  /** Container-Hoehe bei horizontalem Grid. */
+  public static final int HOR_HEIGHT     = 20;
+
+  /** Flag fuer ein horizontales Grid. */
+  public static final int HORIZONTAL = 1;
+  /** Flag fuer ein vertikales Grid. */
+  public static final int VERTICAL = 2;
+
+  /** Speichert die Orientierung des Grid (Horizontal oder Vertikal). */
+  private int orientation = 0;
+
+  /** Karte, an der die Koordinaten-Leiste ausgerichtet wird. */
+  protected JMapPane mapPane = null;
+
+  /** Transformation von Karten-CRS zu CRS des Koordinaten-Rasters */
+  protected MathTransform mapToGrid = null;
+  /** Transformation von CRS des Koordinaten-Rasters zu Karten-CRS*/
+  protected MathTransform gridToMap = null;
+  /** Speichert das CRS, fuer das die Transformationen erstellt wurden. */
+  private CoordinateReferenceSystem transformedMapCRS = null;
+
+  /**
+   * Erzeugt eine Koordinaten-Leiste fuer ein {@link JMapPane}.
+   * @param orientation Orientierung ({@link #HORIZONTAL} oder {@link #VERTICAL})
+   * @param mapPane     Karte an der die Koordinaten-Leiste ausgerichtet wird
+   */
+  public GridPanel(int orientation, JMapPane mapPane) {
+    super();
+
+    this.orientation = orientation;
+    this.mapPane     = mapPane;
+    if ( isVertical() )
+      SwingUtil.setPreferredWidth(this,VERT_WIDTH);
+    else
+      SwingUtil.setPreferredHeight(this,HOR_HEIGHT);
+  }
+
+  /**
+   * Liefert die Orientierung der Koordinaten-Leiste.
+   * @see #HORIZONTAL
+   * @see #VERTICAL
+   */
+  public int getOrientation() {
+    return orientation;
+  }
+
+  /**
+   * Prueft, ob es sich um eine horizontale Koordinaten-Leiste handelt.
+   */
+  public boolean isHorizontal() {
+    return this.orientation == HORIZONTAL;
+  }
+
+  /**
+   * Prueft, ob es sich um eine vertikale Koordinaten-Leiste handelt.
+   */
+  public boolean isVertical() {
+    return this.orientation == VERTICAL;
+  }
+
+  /**
+   * Zeichnet die Koordinaten-Leiste.
+   * @param g Graphics
+   */
+  public void paint(Graphics g) {
+    super.paint(g);
+    if ( getParent() == null || mapPane.getMapArea() == null )
+      return;
+
+    CoordinateReferenceSystem mapCRS = null;   // (aktuelles) CRS des MapPane
+    CoordinateReferenceSystem gridCRS = null;  // CRS fuer die Grad/Min/Sek-Anzeige
+//    try {
+//      final CoordinateReferenceSystem UTM   = CRS.decode("EPSG:32631"); // utm zone 31n
+//      final CoordinateReferenceSystem WGS84 = CRS.decode("EPSG:4326"); // lat/lon (WGS84)
+////      final CoordinateReferenceSystem WGS84 = org.geotools.referencing.crs.DefaultGeographicCRS.WGS84;// lat/lon
+////      final CoordinateReferenceSystem NAD83 = CRS.decode("EPSG:100002"); // lat/lon
+////      mapCRS  = mapPane.getContext().getCoordinateReferenceSystem();
+//      mapCRS = UTM;
+//      gridCRS = WGS84;
+//    } catch (Exception err) {
+//      return;
+//    }
+
+
+    mapCRS  = mapPane.getContext().getCoordinateReferenceSystem();
+    gridCRS = org.geotools.referencing.crs.DefaultGeographicCRS.WGS84;// lat/lon
+//    LOGGER.debug("mapCRS: "+mapCRS);
+//    LOGGER.debug("gridCRS: "+gridCRS);
+
+    double     minX   = mapPane.getMapArea().getMinX();
+    double     minY   = mapPane.getMapArea().getMinY();
+    double     maxX   = mapPane.getMapArea().getMaxX();
+    double     maxY   = mapPane.getMapArea().getMaxY();
+
+// commented out, because it was unused
+//    double     width  = mapPane.getMapArea().getWidth();
+//    double     height = mapPane.getMapArea().getHeight();
+
+    // Minimum/Maximum des Grids in MapPane-CRS (MCRS)
+    double[] mapMin_MCRS = new double[] {minX,minY};
+    double[] mapMax_MCRS = isVertical() ? new double[] {minX,maxY} : new double[] {maxX,minY};
+    // Minimum/Maximum des Grids in Grid-CRS (GCRS)
+    double[] mapMin_GCRS = new double[2];
+    double[] mapMax_GCRS = new double[2];
+
+    try {
+      try {
+        // Der Effizienz halber, die Transformation nur neu ermitteln
+        // wenn sich das Karten-CRS geaendert hat
+        if ( mapToGrid == null || gridToMap == null || transformedMapCRS == null || !transformedMapCRS.equals(mapCRS) ) {
+          mapToGrid = CRS.findMathTransform(mapCRS, gridCRS);
+          gridToMap = CRS.findMathTransform(gridCRS, mapCRS);
+          // CRS merken, fuer das Transformation erstellt wurde
+          transformedMapCRS = mapCRS;
+        }
+      } catch (FactoryException  err) {
+        LOGGER.warn("CRS-Transformation to WGS84 failed: "+err.getMessage());
+        mapToGrid = CRS.findMathTransform(mapCRS, gridCRS, true);
+        gridToMap = CRS.findMathTransform(gridCRS, mapCRS, true);
+        LOGGER.warn("CRS-Transformation without datum shift");
+        // CRS merken, fuer das Transformation erstellt wurde
+        transformedMapCRS = mapCRS;
+      }
+      mapToGrid.transform( mapMin_MCRS, 0, mapMin_GCRS, 0, 1  );
+      mapToGrid.transform( mapMax_MCRS, 0, mapMax_GCRS, 0, 1  );
+    } catch (PointOutsideEnvelopeException err) {
+      return;
+    } catch (Exception err) {
+      LOGGER.error("CRS-Transformation to WGS84 failed: "+err.getMessage());
+      LOGGER.debug("CRS-Transformation to WGS84 failed: "+err.getMessage(),err);
+    }
+
+//   // Ergebnis von Transform: {Latitude,Longitude}
+//   int idx = isVertical() ? 0 : 1;
+   // SEHR SEHR MERKWUERDIG: Mal liefert Transform {Latitude,Longitude}, und
+   //                        manchmal {Longitude,Latitude}!!
+   // WORKAROUND (klappt natuerlich nicht mit allen CRS!):
+   //       Wenn  X_MCRS > Y_MCRS, dann muss auch X_GCRS > Y_GCRS
+  int idx = determineCompatibleArrayIndex(mapMin_MCRS,mapMin_GCRS,mapMax_MCRS,mapMax_GCRS);
+//   LOGGER.debug( isVertical() ? "V" : "H" );
+//   LOGGER.debug( "Min MCRS: "+mapMin_MCRS[0]+", "+mapMin_MCRS[1]+"         GCRS:"+mapMin_GCRS[0]+", "+mapMin_GCRS[1]);
+//   LOGGER.debug( "Max MCRS: "+mapMax_MCRS[0]+", "+mapMax_MCRS[1]+"         GCRS:"+mapMax_GCRS[0]+", "+mapMax_GCRS[1]);
+//   LOGGER.debug( "  --> "+idx+"\n");
+
+   double mapMin = mapMin_GCRS[idx];
+   double mapMax = mapMax_GCRS[idx];
+   // Maximale Groesse des Grid in Pixel
+   int maxSize = isHorizontal() ? getParent().getWidth() : getParent().getHeight();
+
+   // Passende Grid-Unterteilung in Grad
+   double gridDist = determineGridDistance(mapMin,mapMax,maxSize);
+   // Leiste zeichnen
+   if ( isHorizontal() )
+     g.drawLine(0,0,maxSize,0);
+   else
+     g.drawLine(VERT_WIDTH-1,0,VERT_WIDTH-1,maxSize);
+
+   // Abschnitte zeichnen
+   double   firstGrid = Math.ceil(mapMin/gridDist)*gridDist; // 1. Abschnitt in Lat bzw. Lon
+   double[] grid_GCRS = mapMin_GCRS.clone(); // Ausgangspunkt
+   double[] grid_MCRS = new double[2];
+   AffineTransform mapToWin = mapPane.getTransform();
+   for (double gridPos=firstGrid; gridPos<=mapMax; gridPos+=gridDist) {
+     grid_GCRS[idx] = gridPos;
+     // In Map-CRS und dann in Fenster-Koordinaten transformieren
+     double[] grid_WINDOW = new double[2];
+     try {
+       gridToMap.transform(grid_GCRS, 0, grid_MCRS, 0, 1);
+       mapToWin.inverseTransform(grid_MCRS,0,grid_WINDOW,0,1);
+//     } catch (Exception err) {
+     } catch (Throwable err) {
+       LOGGER.warn("Error ignored during paint of coordinate grid: "+err);
+       continue;
+     }
+     // Grid-Abschnitt zeichnen
+     int x1 = isVertical() ? VERT_WIDTH-GRID_LINE_SIZE : (int)grid_WINDOW[0];
+     int y1 = isVertical() ? (int)grid_WINDOW[1] : 0;
+     int x2 = isVertical() ? x1+GRID_LINE_SIZE : x1;
+     int y2 = isVertical() ? y1 : y1+GRID_LINE_SIZE;
+     g.drawLine(x1,y1,x2,y2);
+
+     // Koordinate anzeigen
+     double coord = grid_GCRS[idx];
+     int degrees = (int)coord;
+     int minutes = (int)Math.round((coord-degrees)*60 );
+     // Aufgrund des Minuten-Systems kann schlecht im Vorhinein gerundet
+     // werden. Deshalb wird im Nachhinein ein etwaiger Rundungsfehler
+     // ausgeglichen
+     if ( Math.abs(minutes) >= 60 ) {
+       degrees += Math.signum(minutes);
+       minutes -= Math.signum(minutes) * 60;
+     }
+     String coordStr = Math.abs(degrees)+"°"+Math.abs(minutes);
+     if ( degrees != 0 || minutes != 0 ) {
+       if (isVertical())
+         coordStr += RES.getString( (coord < 0) ? "schmitzm.geotools.gui.GeotoolsGUIUtil.SOUTH.Abb" : "schmitzm.geotools.gui.GeotoolsGUIUtil.NORTH.Abb" );
+       else
+         coordStr += RES.getString( (coord < 0) ? "schmitzm.geotools.gui.GeotoolsGUIUtil.WEST.Abb" : "schmitzm.geotools.gui.GeotoolsGUIUtil.EAST.Abb" );
+     }
+     x1 = isVertical() ?    5 : x1 + 5;
+     y1 = isVertical() ? y1-2 : y1 + 12;
+     g.drawString( coordStr, x1, y1 );
+   }
+
+/////////////   Test und Debugging /////////////////
+//    System.out.println("2 UTM lat="+minY+" lon="+minX+"       --> Degree lat="+dest2[0]+" lon="+dest2[1]);
+
+//    org.geotools.referencing.operation.DefaultMathTransformFactory.main(new String[] {});
+//    if ( debug == 0) {
+//      schmitzm.lang.WorkingThread w = new schmitzm.lang.WorkingThread() {
+//        java.util.Set codes = null;
+//        public void performInit() {
+//          codes = CRS.getSupportedCodes("EPSG");
+//        }
+//        public void performWork() {
+//          for (Object code : codes) {
+//            String crsCode = ((String)code).startsWith("EPSG") ? (String)code : "EPSG:"+((String)code);
+//            try {
+//              CoordinateReferenceSystem crs = CRS.decode(crsCode);
+//              System.out.println(code+"\t"+crsCode+"\t"+crs.getName());
+//            } catch (Exception e) {
+//              System.out.println(code+"\t"+crsCode+"\tError");
+//              break;
+//            }
+//          }
+//        }
+//        public void performDispose() {
+//        }
+//      };
+//      debug = 1;
+//      w.start();
+//    }
+  }
+
+  /**
+   * Bestimmt eine "passende" Unterteilung fuer das Grid.
+   */
+  private static double determineGridDistance(double mapMin_LL, double mapMax_LL, int panelSize) {
+    // Differenz zwischen Min/Max-Koordinaten = darzustellender Bereich in Grad
+    double diff = Math.abs( mapMin_LL - mapMax_LL );
+    // Distanz zwischen zwei Unterteilungen in Grad
+    double dist = 0.0;
+    if ( diff < 10/60.0 )      // < 10 Min. -->  1 Min.-Aufteilung
+      dist = 1/60.0;
+    else if ( diff < 30/60.0 ) // < 30 Min. -->  5 Min.-Aufteilung
+      dist = 5/60.0;
+    else if ( diff <  1 )      // <  1?     --> 10 Min.-Aufteilung
+      dist = 10/60.0;
+    else if ( diff <  3 )      // <  3?     --> 15 Min.-Aufteilung
+      dist = 15/60.0;
+    else if ( diff <  5 )      // <  5?     --> 30 Min.-Aufteilung
+      dist = 30/60.0;
+    else if ( diff < 11 )      // < 11?     -->  1?-Aufteilung
+      dist = 1;
+    else                       // sonst     -->  2?-Aufteilung
+      dist = 2;
+
+    // Solange der Abstand zwischen 2 Unterteilungen weniger als 40 Pixel
+    // betraegt --> Unterteilung verdoppeln
+    while ( diff != 0 && dist != 0 && panelSize / (diff / dist) < 40 )
+      dist *=2;
+
+    return dist;
+  }
+
+//  /**
+//   * Diese Methode stellt einen Workaround fuer einen sehr sehr merkwuerdigen
+//   * {@link MathTransform}-Effekt dar. Mal liefert Transform die Koordinaten
+//   * als {Latitude,Longitude}-Array, und manchmal als {Longitude,Latitude}!
+//   * Diese Methode versucht zu ermitteln, in welchem Array-Index die
+//   * benoetigte Koordinate (je nachdem ob es sich um ein horizontales oder
+//   * vertikales Grid handelt) tatsaechlich befindet.
+//   * @param coord_SCRS Koordinate (in Quell-CRS)
+//   * @param coord_DCRS transformierte Koordinate (in Ziel-CRS)
+//   */
+//  private int determineCompatibleArrayIndex(double[] coord_SCRS, double[] coord_DCRS) {
+//    // SEHR SEHR MERKWUERDIG: Mal liefert Transform {Latitude,Longitude}, und
+//    //                        manchmal {Longitude,Latitude}!!
+//    // WORKAROUND (klappt natuerlich nicht mit allen CRS!):
+//    //       Wenn  X_sourceCRS > Y_sourceCRS, dann muss auch X_destCRS > Y_destCRS
+//    int idx = 0;
+//    if (coord_SCRS[0] > coord_SCRS[1] && coord_DCRS[0] > coord_DCRS[1] ||
+//        coord_SCRS[0] < coord_SCRS[1] && coord_DCRS[0] < coord_DCRS[1] ||
+//        coord_SCRS[0] == coord_SCRS[1] && coord_DCRS[0] == coord_DCRS[1])
+//      idx = isHorizontal() ? 0 : 1;
+//    else
+//      idx = isHorizontal() ? 1 : 0;
+//    return idx;
+//  }
+
+  /**
+   * Diese Methode stellt einen Workaround fuer einen sehr sehr merkwuerdigen
+   * {@link MathTransform}-Effekt dar. Mal liefert Transform die Koordinaten
+   * als {Latitude,Longitude}-Array, und manchmal als {Longitude,Latitude}!
+   * Diese Methode versucht zu ermitteln, in welchem Array-Index die
+   * benoetigte Koordinate (je nachdem ob es sich um ein horizontales oder
+   * vertikales Grid handelt) tatsaechlich befindet.
+   */
+  private int determineCompatibleArrayIndex(double[] mapMin_MCRS, double[] mapMin_GCRS,double[] mapMax_MCRS, double[] mapMax_GCRS) {
+    // SEHR SEHR MERKWUERDIG: Mal liefert Transform {Latitude,Longitude}, und
+    //                        manchmal {Longitude,Latitude}!!
+    // WORKAROUND (klappt natuerlich nicht mit allen CRS!):
+    //       Wenn  X_sourceCRS > Y_sourceCRS, dann muss auch X_destCRS > Y_destCRS
+
+
+    double diff0_GCRS = mapMax_GCRS[0] - mapMin_GCRS[0];
+    double diff1_GCRS = mapMax_GCRS[1] - mapMin_GCRS[1];
+
+    return diff0_GCRS > diff1_GCRS ? 0 : 1;
+  }
+  
+  /**
+   * Nuetzlich wenn die Componente gedruckt (z.B. wenn ein Screenshot gemacht wird) wird. Dann werden wird der
+   * Hintergrund auf WEISS gesetzt.
+   *
+   * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+   *         Kr&uuml;ger</a>
+   */
+  @Override
+  public void print(Graphics g) {
+      Color orig = getBackground();
+      setBackground(Color.WHITE);
+
+      // wrap in try/finally so that we always restore the state
+      try {
+          super.print(g);
+      } finally {
+          setBackground(orig);
+      }
+  }
+
+}

Modified: trunk/src/schmitzm/geotools/gui/JEditorPane.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/JEditorPane.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/JEditorPane.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,933 +1,951 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.gui;
-
-import java.awt.BorderLayout;
-import java.awt.Color;
-import java.awt.Graphics;
-import java.awt.Graphics2D;
-import java.awt.LayoutManager;
-import java.awt.Rectangle;
-import java.awt.event.MouseEvent;
-import java.awt.geom.Point2D;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Stack;
-
-import org.geotools.feature.AttributeType;
-import org.geotools.feature.DefaultFeatureCollection;
-import org.geotools.feature.DefaultFeatureCollections;
-import org.geotools.feature.Feature;
-import org.geotools.feature.FeatureCollection;
-import org.geotools.feature.FeatureType;
-import org.geotools.feature.FeatureTypeBuilder;
-import org.geotools.feature.GeometryAttributeType;
-import org.geotools.feature.SchemaException;
-import org.geotools.feature.type.GeometricAttributeType;
-import org.geotools.map.DefaultMapContext;
-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.renderer.lite.StreamingRenderer;
-import org.geotools.renderer.shape.TransitionShapefileRenderer;
-import org.geotools.styling.Style;
-
-import schmitzm.geotools.feature.FeatureUtil;
-import schmitzm.geotools.feature.FeatureUtil.GeometryForm;
-import schmitzm.geotools.map.event.FeatureModifiedEvent;
-import schmitzm.geotools.map.event.LayerEditCanceledEvent;
-import schmitzm.geotools.map.event.LayerEditFinishedEvent;
-import schmitzm.geotools.map.event.LayerEditStartedEvent;
-import schmitzm.geotools.map.event.MapContextSynchronizer;
-import schmitzm.swing.InputOption;
-import schmitzm.swing.MultipleOptionPane;
-
-import com.vividsolutions.jts.geom.Coordinate;
-import com.vividsolutions.jts.geom.Geometry;
-import com.vividsolutions.jts.geom.LineString;
-import com.vividsolutions.jts.geom.LinearRing;
-import com.vividsolutions.jts.geom.MultiPoint;
-import com.vividsolutions.jts.geom.Point;
-import com.vividsolutions.jts.geom.Polygon;
-
-
-/**
- * The {@code GeoEditorPane} extends the {@link JMapPane} with functionalities
- * to create new vector layers by successively click points via mouse.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class JEditorPane extends JMapPane {
-  /** Modes, the editor can be perform.
-   *  @see JEditorPane#startEditing(EditorMode, String, Style) */
-  public static enum EditorMode {
-    /** Create a new point layer. */
-    New_Point,
-    /** Create a new linestring layer. */
-    New_Line,
-    /** Create a new polygon layer. */
-    New_Polygon
-  }
-
-  /** Attribute name used for the geometry of new layers. */
-  public static final String GEOMETRY_ATTR = "the_geom";
-
-  /** Default-Style for point layers (blue dots). */
-  public static final Style DEFAULT_POINT_STYLE = FeatureUtil.createPointStyle(Color.BLUE);
-  /** Default-Style for line layers (blue lines). */
-  public static final Style DEFAULT_LINE_STYLE = FeatureUtil.createLineStyle(Color.BLUE,2);
-  /** Default-Style for polygon layers (orange with black borders). */
-  public static final Style DEFAULT_POLYGON_STYLE = FeatureUtil.createPolygonStyle(Color.ORANGE, Color.BLUE, 2);
-
-  /** If the edited layer is empty, a dummy feature is inserted, because
-   *  the StreamingRenderer can not handle empty FeatureCollections yet. */
-  private Feature DUMMY_EDITOR_FEATURE = null;
-  private Feature DUMMY_LINE_FEATURE = null;
-  private Feature DUMMY_POINT_FEATURE = null;
-
-  /** The map context of the displayed layer. */
-  protected MapContext mapContext = null;
-
-  /** Contains the additional attributes for new FeatureCollections. */
-  protected FeatureType additionalAttr = null;
-  /** Contains the {@link InputOption} to specify the additional
-   *  attribute values.  */
-  protected FeatureInputOption attrInputOption = null;
-
-  /** The map context where the edited layers are displayed. This
-   *  context is displayed on top of the other layers. */
-  protected MapContext editorMapContext = null;
-  /** The renderer the edited layers are rendered with. */
-  protected GTRenderer editorRenderer = null;
-  /** Holds the {@link Style styles} to display edited layers. */
-  protected Map<GeometryForm,Style> editorStyles = null;
-  /** Holds the operation the editor currently performs. */
-  protected EditorMode editorMode = null;
-
-  /** Holds the {@link FeatureType} of the edited layer. */
-  protected FeatureType editorFeatureType = null;
-  /** Holds the kind of geometry of the edited layer. */
-  protected GeometryForm editorGeometryForm = null;
-  /** Holds the {@link FeatureCollection} of the edited layer. */
-  protected DefaultFeatureCollection editorFeatureCollection = null;
-  /** Holds the edited layer. */
-  protected MapLayer editorLayer = null;
-
-  /** Holds the {@link FeatureType} of the new segment (incomplete Feature)
-   *  displayed as line. */
-  protected FeatureType segmLineFeatureType = null;
-  /** Holds the {@link FeatureCollection} which holds the new segment
-   *  (incomplete Feature) displayed as line. */
-  protected DefaultFeatureCollection segmLineFeatureCollection = null;
-  /** Holds the layer, the new segment (incomplete Feature) is displayed in
-   *  as line. */
-  protected MapLayer segmLineLayer = null;
-
-  /** Holds the {@link FeatureType} of the new segment (incomplete Feature)
-   *  displayed as points. */
-  protected FeatureType segmPointFeatureType = null;
-  /** Holds the {@link FeatureCollection} which holds the new segment
-   *  (incomplete Feature) displayed as points. */
-  protected DefaultFeatureCollection segmPointFeatureCollection = null;
-  /** Holds the layer, the new segment (incomplete Feature) is displayed in
-   *  as points. */
-  protected MapLayer segmPointLayer = null;
-
-
-  /** Holds the points of the edited segment (incomplete Feature) which
-   *  can be undone. */
-  protected Stack<Coordinate> segmUndoPoints = new Stack<Coordinate>();
-  /** Holds the undone points of the edited segment (incomplete Feature) which
-   *  can be redone. */
-  protected Stack<Coordinate> segmRedoPoints = new Stack<Coordinate>();
-  /** Holds the points of former segments (complete Features) which
-   *  can be undone. */
-  protected Stack<Stack<Coordinate>> globalUndoPoints = new Stack<Stack<Coordinate>>();
-  /** Holds the undone points of former segments (complete Features) which
-   *  can be redone. */
-  protected Stack<Stack<Coordinate>> globalRedoPoints = new Stack<Stack<Coordinate>>();
-  /** Holds the former segments (complete Features) which can be undone. */
-  protected Stack<Feature> globalUndoFeatures = new Stack<Feature>();
-  /** Holds the undone segments (complete Features) which can be redone. */
-  protected Stack<Feature> globalRedoFeatures = new Stack<Feature>();
-
-  /**
-   * Creates a new {@code GeoEditorPane}.
-   */
-  public JEditorPane() {
-    this( new BorderLayout(),
-          true,
-          new TransitionShapefileRenderer(),
-          new DefaultMapContext(DefaultGeographicCRS.WGS84)
-    );
-  }
-
-  /**
-   * Creates a new {@code GeoEditorPane}. This constructor provides the possibility
-   * to use alternative implementations of the internal components.
-   * <b>The specified parameter all can be {@code null}! In this case
-   * the respective default component is used.</b>
-   */
-  public JEditorPane(LayoutManager layout, boolean isDoubleBuffered, GTRenderer renderer, MapContext context) {
-    super(layout,isDoubleBuffered,renderer,context);
-    this.mapContext = getContext();
-    // initalize the editor styles
-    this.editorStyles = new HashMap<GeometryForm, Style>();
-    for (GeometryForm geomForm : GeometryForm.values())
-      this.setEditorStyle(geomForm, null);
-
-    // no standard action on left mouse button, instead: adding points
-    setState( NONE );
-    setWindowSelectionState( ZOOM_IN );
-    // special map context for the editor layers, so the
-    // editor layers are not shown in "normal" layer list
-    this.editorRenderer   = new TransitionShapefileRenderer();
-    this.editorMapContext = new DefaultMapContext( mapContext.getCoordinateReferenceSystem() );
-    // listen to CRS/Area changes on the "normal" Context to
-    // synchronize the editor context
-    this.mapContext.addMapBoundsListener( new MapContextSynchronizer(editorMapContext) );
-
-    // create the input option to specify additional attribute values
-    attrInputOption = new FeatureInputOption(null,true,(Feature)null);
-  }
-
-  /**
-   * After the actions of the super method, this method paints the
-   * special editor layers in {@link #editorMapContext}.
-   */
-  protected void paintComponent(Graphics g) {
-    resetEditorLayerVisibility();
-    super.paintComponent(g);
-    Rectangle r = getBounds();
-    Rectangle dr = new Rectangle(r.width, r.height);
-    editorRenderer.setContext(editorMapContext);
-    editorRenderer.paint((Graphics2D) g, dr, mapArea);
-  }
-
-  /**
-   * Ignores the actions of the super class for left-clicks.
-   * Instead this method reacts according to the current
-   * editor mode.
-   */
-  public void mouseClicked(MouseEvent e) {
-    Point2D geoCoord = getTransform().transform(e.getPoint(), null);
-    // Zunaechst Modus auf NULL pruefen, da ansonsten
-    // NullPointerException in switch-Statement
-    if ( editorMode == null )
-      return;
-
-    switch( editorMode ) {
-      case New_Point:
-      case New_Line:
-      case New_Polygon: addSegment( new Coordinate(geoCoord.getX(), geoCoord.getY()) );
-                        break;
-    }
-  }
-
-  //**********************************************************************
-  //***** General public methods
-  //**********************************************************************
-
-  /**
-   * Checks, whether a layer is edited.
-   */
-  public boolean isEditorEnabled() {
-    return editorMode != null;
-  }
-
-  /**
-   * Sets the style for edited layers.
-   * @param geomForm kind of layers the style is set for
-   * @param style a Style (if {@code null} a default style is set, so
-   *              {@link #getEditorStyle(GeometryForm)} never returns null)
-   */
-  public void setEditorStyle(GeometryForm geomForm, Style style) {
-    // If no style is specified, set a default style
-    if ( style == null )
-      switch ( geomForm ) {
-        case POINT:   style = DEFAULT_POINT_STYLE; break;
-        case LINE:    style = DEFAULT_LINE_STYLE; break;
-        case POLYGON: style = DEFAULT_POLYGON_STYLE; break;
-      }
-
-    // Set the style
-    editorStyles.put(geomForm, style);
-
-    // Apply the style also to the current edited layer
-    if ( editorLayer != null && FeatureUtil.getGeometryForm(editorLayer) == geomForm )
-      editorLayer.setStyle(style);
-    if ( segmLineLayer != null && FeatureUtil.getGeometryForm(segmLineLayer) == geomForm )
-      segmLineLayer.setStyle(style);
-    if ( segmPointLayer != null && FeatureUtil.getGeometryForm(segmPointLayer) == geomForm )
-      segmPointLayer.setStyle(style);
-  }
-
-  /**
-   * Returns the style for edited layers.
-   * @param geomForm type of layers the style is returned for
-   */
-  public Style getEditorStyle(GeometryForm geomForm) {
-    return this.editorStyles.get(geomForm);
-  }
-
-  /**
-   * Returns the style for the current edited layer.
-   */
-  public Style getEditorStyle() {
-    if ( editorGeometryForm == null )
-      return null;
-    return this.editorStyles.get(editorGeometryForm);
-  }
-
-  /**
-   * Sets the additional attributes for new FeatureCollections (besides
-   * the geometric attribute, which is added automatically).
-   * @param fType defines the attributes (If {@code null}, new FeatureCollections
-   *              only contain the geometric attribute)
-   */
-  public void setAdditionalAttributes(FeatureType fType) {
-    this.additionalAttr = fType;
-  }
-
-  /**
-   * Returns the additional attributes for new FeatureCollections (besides
-   * the geometric attribute, which is added automatically).
-   */
-  public FeatureType getAdditionalAttributes() {
-    return this.additionalAttr;
-  }
-
-  /**
-   * Returns the current editor mode.
-   */
-  public EditorMode getEditorMode() {
-    return this.editorMode;
-  }
-
-  /**
-   * Returns the edited layer.
-   */
-  public MapLayer getEditorLayer() {
-    return this.editorLayer;
-  }
-
-  /**
-   * Returns the {@link FeatureCollection} of the edited layer.
-   */
-  public FeatureCollection getEditorFeatureCollection() {
-    return this.editorFeatureCollection;
-  }
-
-  //**********************************************************************
-  //*****  Public Methods controlling the editor operations
-  //**********************************************************************
-
-  /**
-   * Starts a new layer.
-   * @param mode type of layer
-   * @param layerTitle Title for the new layer
-   * @exception UnsupportedOperationException if no map area is defined yet
-   */
-  public void startEditing(EditorMode mode, String layerTitle) {
-    // to create a new layer, first an existing layer must be
-    // displayed, so that a CRS and geo-position is available
-    // for the new layer
-    if ( getMapArea() == null )
-      throw new UnsupportedOperationException( GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.gui.JEditorPane.Err.MissingMap") );
-    // cancel active editings
-    cancelEditing();
-    editorMode = mode;
-
-    // Create new Layers
-    initEditorFeatureCollection(layerTitle);
-    initSegmentFeatureCollection();
-    editorMapContext.addLayer(0,editorLayer);
-    fireMapPaneEvent( new LayerEditStartedEvent(this,editorLayer,this) );
-  }
-
-  /**
-   * Called when the mouse is clicked on map during creating a new layer.
-   * @param coord World coordinates of click position
-   * @param refresh indicates whether the visualisation will be refreshed
-   * @param aClearRedo indicates whether the REDO-Stack is cleared (normally {@code true},
-   *                   but {@code false} during REDO operation!)
-   */
-  protected void addSegment(Coordinate coord, boolean refresh, boolean clearRedo) {
-    if ( editorMode != EditorMode.New_Point &&
-         editorMode != EditorMode.New_Line &&
-         editorMode != EditorMode.New_Polygon )
-      return;
-
-    // store the new point for undoing
-    segmUndoPoints.push(coord);
-    // delete all former redo possibilities
-    if ( clearRedo )
-      segmRedoPoints.clear();
-    // recreate the segment FeatureCollection to show the extended line
-    generateSegmentFeatureCollection();
-
-    // finish the feature automatically
-    // - when editing points, because there are no segments for point layer,
-    //   because every point is a new feature
-    // - when editing polygons and reaching the start point
-    if ( editorGeometryForm == GeometryForm.POINT ||
-         editorGeometryForm == GeometryForm.POLYGON && segmUndoPoints.size() > 1 && segmUndoPoints.lastElement().equals(segmUndoPoints.firstElement()) )
-      finishFeature(refresh, clearRedo); // refresh is done by finishFeature()
-    else
-      if ( refresh )
-        refresh();
-  }
-
-  /**
-   * Called when the mouse is clicked on map during creating a new layer.
-   * @param coord World coordinates of click position
-   */
-  protected void addSegment(Coordinate coord) {
-    addSegment(coord, true, true);
-  }
-
-  /**
-   * Finishes the editing of the current segment (Feature).
-   * If no editing operation is currently in progress, this method does nothing.
-   * @param refresh indicates whether the visualisation will be refreshed
-   * @param aClearRedo indicates whether the REDO-Stack is cleared (normally {@code true},
-   *                   but {@code false} during REDO operation!)
-   * @exception UnsupportedOperationException if a line or polygon feature can not
-   *            be finished because of less specified points
-   */
-  protected void finishFeature(boolean refresh, boolean clearRedo) {
-    if ( editorMode == null )
-      return;
-
-    if ( editorGeometryForm == GeometryForm.LINE && segmUndoPoints.size() < 2 )
-      throw new UnsupportedOperationException( GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.gui.JEditorPane.Err.Line.LessPoints") );
-    if ( editorGeometryForm == GeometryForm.POLYGON && segmUndoPoints.size() < 3 )
-      throw new UnsupportedOperationException( GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.gui.JEditorPane.Err.Polygon.LessPoints") );
-
-    // close a polygon automatically
-    if ( editorGeometryForm == GeometryForm.POLYGON &&
-        !segmUndoPoints.lastElement().equals(segmUndoPoints.firstElement()) ) {
-      addSegment( segmUndoPoints.firstElement(), refresh, clearRedo );
-      return; // !!!! finishFeature(.) is called again by addSegment(..) !!!!
-    }
-    // create a new Feature from the segment points
-    Feature feature = createFeature();
-    if ( feature == null )
-      return;
-    fireMapPaneEvent( new FeatureModifiedEvent(this,editorLayer,feature,this) );
-
-    // update the global undo
-    globalUndoPoints.push( segmUndoPoints );
-    globalUndoFeatures.push( feature );
-    editorFeatureCollection.add( feature );
-
-    // after finishing a Feature, a new segment is started
-    segmUndoPoints = new Stack<Coordinate>();
-    if ( clearRedo )
-      segmRedoPoints = globalRedoPoints.isEmpty() ? new Stack<Coordinate>() : globalRedoPoints.pop();
-    initSegmentFeatureCollection();
-    // refresh the display
-    if ( refresh )
-      refresh();
-  }
-
-  /**
-   * Finishes the editing of the current segment (Feature).
-   * If no editing operation is currently in progress, this method does nothing.
-   */
-  public void finishFeature() {
-    finishFeature(true, true);
-  }
-
-  /**
-   * Finishes the current editing operation. After that no more operations
-   * on this layer can be performed.
-   * As long as no other editing operation is started, the edited (new) layer is
-   * available by {@link #getEditorLayer()} and {@link #getEditorFeatureCollection()}.
-   * If no editing operation is currently in progress, this method does nothing.
-   */
-  public void finishEditing() {
-    if ( editorMode == null )
-      return;
-
-    // if current segment is not closed, finish it automatically
-    if ( !segmUndoPoints.isEmpty() )
-      finishFeature();
-    initUndoRedo();
-
-    // move the edited layer to the "real" MapContext
-    editorMapContext.removeLayer(editorLayer);
-    if ( mapContext.indexOf(editorLayer) < 0 ) {
-      mapContext.addLayer(editorLayer);
-      editorLayer.setVisible(true);
-    }
-    fireMapPaneEvent( new LayerEditFinishedEvent(this,editorLayer,this) );
-
-    // initialize the editing variables
-    editorMode = null;
-    editorLayer = null;
-    editorFeatureCollection = null;
-    editorGeometryForm = null;
-
-    // refresh the display
-    refresh();
-  }
-
-  /**
-   * Cancels the current edititing operation. The edited layer is removed.
-   */
-  public void cancelEditing() {
-    if ( editorLayer != null )
-      this.editorMapContext.removeLayer( editorLayer );
-    if ( editorFeatureCollection != null ) {
-      if ( mapContext.indexOf(editorLayer) < 0 ) {
-        // Layer was a new one, so clear it completly
-        editorFeatureCollection.clear();
-        initUndoRedo();
-        fireMapPaneEvent( new LayerEditCanceledEvent(this,null,this) );
-      } else {
-        // Layer was an existing one, so undo all editing operations
-        undoAll();
-        initUndoRedo();
-        fireMapPaneEvent( new LayerEditFinishedEvent(this,editorLayer,this) );
-      }
-    }
-    if ( segmLineFeatureCollection != null )
-      segmLineFeatureCollection.clear();
-    if ( segmPointFeatureCollection != null )
-      segmPointFeatureCollection.clear();
-
-    // initialize the editing variables
-    editorMode = null;
-    editorLayer = null;
-    editorFeatureCollection = null;
-    editorGeometryForm = null;
-
-    // refresh the display
-    refresh();
-  }
-
-  /**
-   * Makes previously made editing actions undone.
-   * @param count count of operations made undone
-   */
-  public void undoEditing(int count) {
-    for (int i=0; i<count; i++)
-    {
-      if ( segmUndoPoints.isEmpty() ) {
-        if ( globalUndoPoints.isEmpty() )
-          // No more undo operations available
-          break;
-        else {
-          segmUndoPoints = globalUndoPoints.pop();
-          editorFeatureCollection.remove( globalUndoFeatures.peek() );
-
-          globalRedoFeatures.push( globalUndoFeatures.pop() );
-          if ( !segmRedoPoints.isEmpty() )
-            globalRedoPoints.push( segmRedoPoints );
-          segmRedoPoints = new Stack<Coordinate>();
-
-          // On lines the last point and finish feature operation
-          // are separated, so they also must be undone
-          // separately.
-          if ( editorGeometryForm == GeometryForm.LINE ) {
-            generateSegmentFeatureCollection();
-            continue;
-          }
-        }
-      }
-      segmRedoPoints.push( segmUndoPoints.pop() );
-      generateSegmentFeatureCollection();
-    }
-    refresh();
-  }
-
-  /**
-   * Makes the last made editing action undone.
-   */
-  public void undoEditing() {
-    undoEditing(1);
-  }
-
-  /**
-   * Makes all made editing action undone.
-   */
-  public void undoAll() {
-    undoEditing( Integer.MAX_VALUE );
-  }
-
-  /**
-   * Checks wheater a undo operation can be performed.
-   */
-  public boolean isUndoPossible() {
-    return !segmUndoPoints.isEmpty() || !globalUndoPoints.isEmpty();
-  }
-
-  /**
-   * Restores previous undone editing actions.
-   * @param count count of redo operations
-   */
-  public void redoEditing(int count) {
-    for (int i=0; i<count; i++)
-    {
-      if ( segmRedoPoints.isEmpty() ) {
-        if ( globalRedoPoints.isEmpty() )
-          // No more redo operations available
-          break;
-        else {
-          // Lines must be finished when all segment redo operations
-          // are redone; Points and Polygons must not, because they
-          // were already closed on last addSegment(.) (closing point
-          // of polygon is also a part of the redo stack!)
-          if ( editorGeometryForm == GeometryForm.LINE )
-            finishFeature(false, false);
-          segmRedoPoints = globalRedoPoints.pop();
-        }
-      }
-      addSegment( segmRedoPoints.pop(), false, false );
-    }
-    refresh();
-  }
-
-  /**
-   * Restores the last undone editing action.
-   */
-  public void redoEditing() {
-    redoEditing(1);
-  }
-
-  /**
-   * Checks wheater a redo operation can be performed.
-   */
-  public boolean isRedoPossible() {
-    // Redo possible if
-    // - some operations of the current segment can be redone
-    // - some operations of former segments can be redone
-    return !segmRedoPoints.isEmpty() || !globalRedoPoints.isEmpty();
-  }
-
-  //**********************************************************************
-  //*****  Helper methods for the editor operations
-  //**********************************************************************
-  /**
-   * Sets {@link #editorFeatureCollection} and {@link #editorLayer} to completely
-   * new instances.
-   * @param title title for the new layer
-   */
-  protected void initUndoRedo() {
-    // initialize the Undo/Redo-Stacks
-    for ( Stack s : globalRedoPoints ) s.clear();
-    for ( Stack s : globalUndoPoints ) s.clear();
-    globalRedoPoints.clear();
-    globalUndoPoints.clear();
-    globalRedoFeatures.clear();
-    globalUndoFeatures.clear();
-    segmRedoPoints.clear();
-    segmUndoPoints.clear();
-  }
-
-  /**
-   * Sets {@link #editorFeatureCollection} and {@link #editorLayer} to completely
-   * new instances.
-   * @param title title for the new layer
-   */
-  protected void initEditorFeatureCollection(String title) {
-    // create the new layer
-    editorFeatureCollection = (DefaultFeatureCollection)DefaultFeatureCollections.newCollection(title);
-    editorFeatureType       = createFeatureType(editorMode, getAdditionalAttributes());
-    DUMMY_EDITOR_FEATURE    = createDummyFeature(editorFeatureType);
-    editorFeatureCollection.add(DUMMY_EDITOR_FEATURE);
-    editorGeometryForm      = FeatureUtil.getGeometryForm(editorFeatureCollection);
-    editorLayer             = new DefaultMapLayer(editorFeatureCollection,getEditorStyle(editorGeometryForm));
-    editorLayer.setTitle(title);
-  }
-
-  /**
-   * Clears the {@link FeatureCollection} used to handle the current
-   * edited segment.
-   */
-  protected void initSegmentFeatureCollection() {
-    // initialize the segment to start a new feature
-    if ( segmLineFeatureCollection == null ) {
-      // initialize the objects used to display the
-      // current segment as line
-      segmLineFeatureCollection = (DefaultFeatureCollection)DefaultFeatureCollections.newCollection("SegmentAsLine");
-      segmLineFeatureType       = createFeatureType(LineString.class, null);
-      DUMMY_LINE_FEATURE        = createDummyFeature(segmLineFeatureType);
-      segmLineFeatureCollection.add(DUMMY_LINE_FEATURE);
-      segmLineLayer             = new DefaultMapLayer(segmLineFeatureCollection,getEditorStyle(GeometryForm.LINE));
-      segmLineLayer.setTitle("Line layer for current segment");
-      editorMapContext.addLayer(segmLineLayer);
-      // initialize the objects used to display the
-      // current segment as points
-      segmPointFeatureCollection = (DefaultFeatureCollection)DefaultFeatureCollections.newCollection("SegmentAsPoints");
-      segmPointFeatureType       = createFeatureType(MultiPoint.class, null);
-      DUMMY_POINT_FEATURE        = createDummyFeature(segmPointFeatureType);
-      segmPointFeatureCollection.add(DUMMY_POINT_FEATURE);
-      segmPointLayer             = new DefaultMapLayer(segmPointFeatureCollection,getEditorStyle(GeometryForm.POINT));
-      segmPointLayer.setTitle("Point layer for current segment");
-      editorMapContext.addLayer(segmPointLayer);
-    } else {
-      segmLineFeatureCollection.clear();
-      segmPointFeatureCollection.clear();
-    }
-  }
-
-  /**
-   * Creates a new segment Feature from the currently selected points.
-   */
-  protected void generateSegmentFeatureCollection() {
-    initSegmentFeatureCollection();
-    // show the segment as single points
-    Feature segmPointFeature = createSegmentPointFeature();
-    if ( segmPointFeature != null )
-      segmPointFeatureCollection.add( segmPointFeature );
-    // show the segment as a line
-    Feature segmLineFeature = createSegmentLineFeature();
-    if ( segmLineFeature != null )
-      segmLineFeatureCollection.add( segmLineFeature );
-    // Fire event even if no (real) feature is created!
-    fireMapPaneEvent( new FeatureModifiedEvent(this,segmLineLayer,segmLineFeature,this) );
-  }
-
-  /**
-   * Creates a new {@link Feature Line-Feature} from the currently selected
-   * segment points.
-   */
-  protected Feature createSegmentLineFeature() {
-    // Line can only be created with at least 2 points
-    // For point layer the segment is not shown
-    if ( segmUndoPoints.size() < 2 ||
-         editorGeometryForm == GeometryForm.POINT )
-      return null;
-
-    Coordinate[] coord      = segmUndoPoints.toArray(new Coordinate[0]);
-    LineString   lineString = createGeometryFromPoints(LineString.class, coord);
-    try {
-      return segmLineFeatureType.create( new Object[] {lineString} );
-    } catch (Exception e) {
-      throw new RuntimeException(e);
-    }
-  }
-
-  /**
-   * Creates a new {@link Feature MultiPoint-Feature} from the currently selected
-   * segment points.
-   */
-  protected Feature createSegmentPointFeature() {
-    // Point can only be created with at least 1 point
-    // For point layer the segment is not shown
-    if ( segmUndoPoints.size() < 1 ||
-         editorGeometryForm == GeometryForm.POINT )
-      return null;
-
-    Coordinate[] coord      = segmUndoPoints.toArray(new Coordinate[0]);
-    MultiPoint   multiPoint = createGeometryFromPoints(MultiPoint.class, coord);
-    try {
-      return segmPointFeatureType.create( new Object[] {multiPoint} );
-    } catch (Exception e) {
-      throw new RuntimeException(e);
-    }
-  }
-
-  /**
-   * Creates a new Feature from the currently selected points. The non-geometric
-   * attributes are set to default values.
-   */
-  private Feature createFeature() {
-    Coordinate[] coord   = segmUndoPoints.toArray(new Coordinate[0]);
-    Feature      feature = null;
-    try {
-      // if a feature was undone previously use this as
-      // default for the new feature
-      if ( !globalRedoFeatures.isEmpty() )
-        feature = globalRedoFeatures.pop();
-      else {
-        // generate default attribute values
-        Object[] attr = FeatureUtil.getDefaultAttributeValues(editorFeatureType);
-        // replace default attribute values with auto generate
-        // values (for all registered attributes)
-        for (int i=0; i<attr.length; i++) {
-          AttributeType aType = editorFeatureType.getAttributeType(i);
-          if ( FeatureUtil.getAutoValueGenerator(aType) != null )
-            attr[i] = FeatureUtil.getNextAutoValue(aType);
-        }
-        // create new feature
-        feature = editorFeatureType.create(attr);
-      }
-      feature.setDefaultGeometry(
-          createGeometryFromPoints(getGeometryType(editorMode), coord )
-      );
-
-      if ( feature.getNumberOfAttributes() > 1 ) {
-        attrInputOption.setValue(feature);
-        Object[] value = MultipleOptionPane.showMultipleInputDialog(
-                            this,
-                            GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.gui.JEditorToolBar.NewFeature.title"),
-                            attrInputOption
-        );
-        if ( value == null )
-          return null;
-      }
-      return feature;
-    } catch (Exception e) {
-      throw new RuntimeException(e);
-    }
-
-  }
-
-
-  //**********************************************************************
-  //*****  Helper methods to deal with geometries
-  //**********************************************************************
-  /**
-   * Determines the geometry type to deal with according to the
-   * editor mode.
-   * @param mode editor mode
-   */
-  private static Class<? extends Geometry> getGeometryType(EditorMode mode) {
-    switch( mode ) {
-      case New_Point:   return Point.class;
-      case New_Line:    return LineString.class;
-      case New_Polygon: return Polygon.class;
-    }
-    return null;
-  }
-
-  /**
-   * Creates a geometry (point, linestring/ring, polygon) from a set of points. If
-   * no points are specified ({@code null}), a default geometry is created.
-   * @param gtype type of geometry
-   * @param coord set of points (can be {@code null})
-   */
-  private static <G extends Geometry> G createGeometryFromPoints(Class<G> gtype, Coordinate[] coord) {
-    // Point
-    if ( gtype.isAssignableFrom( com.vividsolutions.jts.geom.Point.class ) ) {
-      if ( coord == null )
-        coord = new Coordinate[] { new Coordinate() };
-      return (G)FeatureUtil.GEOMETRY_FACTORY.createPoint( coord[0] );
-    }
-    // MultiPoint
-    if ( gtype.isAssignableFrom( com.vividsolutions.jts.geom.MultiPoint.class ) ) {
-      if ( coord == null )
-        coord = new Coordinate[] { new Coordinate() };
-      return (G)FeatureUtil.GEOMETRY_FACTORY.createMultiPoint( coord );
-    }
-    // LineString
-    if ( gtype.isAssignableFrom( com.vividsolutions.jts.geom.LineString.class ) ) {
-      if ( coord != null && coord.length > 2 && coord[0].equals(coord[coord.length-1]) )
-        return (G)FeatureUtil.GEOMETRY_FACTORY.createLinearRing(coord);
-      return (G)FeatureUtil.GEOMETRY_FACTORY.createLineString(coord);
-    }
-    // Polygon
-    if ( gtype.isAssignableFrom( com.vividsolutions.jts.geom.Polygon.class ) ) {
-      LinearRing shell = null;
-      if ( coord != null && coord.length > 2 && coord[0].equals(coord[coord.length-1]) )
-        shell = FeatureUtil.GEOMETRY_FACTORY.createLinearRing(coord);
-      return (G)FeatureUtil.GEOMETRY_FACTORY.createPolygon(shell,null);
-    }
-
-    throw new UnsupportedOperationException("Can not create geometry for "+gtype.getName());
-  }
-
-  /**
-   * Extends a feature type with a default geometry attribute.
-   * @param gtype default geometry of the new feature type
-   * @param ftype a feature type which is extended (can be {@code null})
-   */
-  private FeatureType createFeatureType(Class<? extends Geometry> gtype, FeatureType ftype) {
-    GeometryAttributeType geomAttrType = new GeometricAttributeType(
-        GEOMETRY_ATTR,
-        gtype,
-        false,
-        createGeometryFromPoints(gtype,null),
-        mapContext.getCoordinateReferenceSystem(),
-        null
-    );
-    String ftypeName           = ftype != null ? ftype.getTypeName() : gtype.getSimpleName()+"_feature";
-    FeatureTypeBuilder builder = FeatureTypeBuilder.newInstance(ftypeName);
-    builder.setDefaultGeometry( geomAttrType );
-    if ( ftype != null )
-      builder.addTypes( ftype.getAttributeTypes() );
-    try {
-      return builder.getFeatureType();
-    } catch ( SchemaException err ) {
-      throw new RuntimeException(err);
-    }
-  }
-
-  /**
-   * Extends a feature type with a default geometry attribute.
-   * @param mode  specifies the the default geometry used for the feature type
-   * @param ftype a feature type which is extended (can be {@code null})
-   */
-  private FeatureType createFeatureType(EditorMode mode, FeatureType ftype) {
-    Class<? extends Geometry> gtype = null;
-    switch( mode ) {
-      case New_Point:   gtype = Point.class; break;
-      case New_Line:    gtype = LineString.class; break;
-      case New_Polygon: gtype = Polygon.class; break;
-    }
-    return createFeatureType(gtype,ftype);
-  }
-
-  /**
-   * Creates a feature with default values for a given feature type.
-   * @param ftype a feature type
-   */
-  private static Feature createDummyFeature(FeatureType ftype) {
-    try {
-      return ftype.create( FeatureUtil.getDefaultAttributeValues(ftype) );
-    } catch (Exception e) {
-      throw new RuntimeException(e);
-    }
-  }
-
-  /**
-   * Checks, whether the editor layer is empty. If it is, a dummy feature is inserted
-   * because the StreamingRenderer can not handle empty Feature-Layers yet
-   * (also if the layer is hidden!).
-   * At the moment, the first a feature is added, the dummy feature is removed, so
-   * is is not displayed any time.
-   */
-  private void resetEditorLayerVisibility() {
-    // if layer is empty, insert a Dummy-Feature (and hide the
-    // layer) because the StreamingRenderer can not handle empty
-    // Feature-Layers yet
-    if ( segmLineFeatureCollection != null && segmLineFeatureCollection.size() == 0 )
-      segmLineFeatureCollection.add( DUMMY_LINE_FEATURE );
-    if ( segmPointFeatureCollection != null && segmPointFeatureCollection.size() == 0 )
-      segmPointFeatureCollection.add( DUMMY_POINT_FEATURE );
-    if ( editorFeatureCollection != null && editorFeatureCollection.size() == 0 )
-      editorFeatureCollection.add( DUMMY_EDITOR_FEATURE );
-
-    // if the layer is not empty anymore, remove the Dummy-Feature, so
-    // it is not displayed
-    if ( segmLineFeatureCollection != null && segmLineFeatureCollection.size() == 2 )
-      segmLineFeatureCollection.remove( DUMMY_LINE_FEATURE );
-    if ( segmPointFeatureCollection != null && segmPointFeatureCollection.size() == 2 )
-      segmPointFeatureCollection.remove( DUMMY_POINT_FEATURE );
-    if ( editorFeatureCollection != null && editorFeatureCollection.size() == 2 )
-      editorFeatureCollection.remove( DUMMY_EDITOR_FEATURE );
-
-    // hide the editor layer if it only contains the dummy feature
-    if ( editorLayer != null )
-      editorLayer.setVisible(editorFeatureCollection.size() > 1 || !editorFeatureCollection.contains(DUMMY_EDITOR_FEATURE));
-    if ( segmLineLayer != null )
-      segmLineLayer.setVisible(segmLineFeatureCollection.size() > 1 || !segmLineFeatureCollection.contains(DUMMY_LINE_FEATURE));
-    if ( segmPointLayer != null )
-      segmPointLayer.setVisible(segmPointFeatureCollection.size() > 1 || !segmPointFeatureCollection.contains(DUMMY_POINT_FEATURE));
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.gui;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.LayoutManager;
+import java.awt.Rectangle;
+import java.awt.event.MouseEvent;
+import java.awt.geom.Point2D;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Stack;
+
+import org.geotools.feature.AttributeType;
+import org.geotools.feature.DefaultFeatureCollection;
+import org.geotools.feature.DefaultFeatureCollections;
+import org.geotools.feature.Feature;
+import org.geotools.feature.FeatureCollection;
+import org.geotools.feature.FeatureType;
+import org.geotools.feature.FeatureTypeBuilder;
+import org.geotools.feature.GeometryAttributeType;
+import org.geotools.feature.SchemaException;
+import org.geotools.feature.type.GeometricAttributeType;
+import org.geotools.map.DefaultMapContext;
+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.renderer.lite.StreamingRenderer;
+import org.geotools.renderer.shape.TransitionShapefileRenderer;
+import org.geotools.styling.Style;
+
+import schmitzm.geotools.feature.FeatureUtil;
+import schmitzm.geotools.feature.FeatureUtil.GeometryForm;
+import schmitzm.geotools.map.event.FeatureModifiedEvent;
+import schmitzm.geotools.map.event.LayerEditCanceledEvent;
+import schmitzm.geotools.map.event.LayerEditFinishedEvent;
+import schmitzm.geotools.map.event.LayerEditStartedEvent;
+import schmitzm.geotools.map.event.MapContextSynchronizer;
+import schmitzm.swing.InputOption;
+import schmitzm.swing.MultipleOptionPane;
+
+import com.vividsolutions.jts.geom.Coordinate;
+import com.vividsolutions.jts.geom.Geometry;
+import com.vividsolutions.jts.geom.LineString;
+import com.vividsolutions.jts.geom.LinearRing;
+import com.vividsolutions.jts.geom.MultiPoint;
+import com.vividsolutions.jts.geom.Point;
+import com.vividsolutions.jts.geom.Polygon;
+
+
+/**
+ * The {@code GeoEditorPane} extends the {@link JMapPane} with functionalities
+ * to create new vector layers by successively click points via mouse.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class JEditorPane extends JMapPane {
+  /** Modes, the editor can be perform.
+   *  @see JEditorPane#startEditing(EditorMode, String, Style) */
+  public static enum EditorMode {
+    /** Create a new point layer. */
+    New_Point,
+    /** Create a new linestring layer. */
+    New_Line,
+    /** Create a new polygon layer. */
+    New_Polygon
+  }
+
+  /** Attribute name used for the geometry of new layers. */
+  public static final String GEOMETRY_ATTR = "the_geom";
+
+  /** Default-Style for point layers (blue dots). */
+  public static final Style DEFAULT_POINT_STYLE = FeatureUtil.createPointStyle(Color.BLUE);
+  /** Default-Style for line layers (blue lines). */
+  public static final Style DEFAULT_LINE_STYLE = FeatureUtil.createLineStyle(Color.BLUE,2);
+  /** Default-Style for polygon layers (orange with black borders). */
+  public static final Style DEFAULT_POLYGON_STYLE = FeatureUtil.createPolygonStyle(Color.ORANGE, Color.BLUE, 2);
+
+  /** If the edited layer is empty, a dummy feature is inserted, because
+   *  the StreamingRenderer can not handle empty FeatureCollections yet. */
+  private Feature DUMMY_EDITOR_FEATURE = null;
+  private Feature DUMMY_LINE_FEATURE = null;
+  private Feature DUMMY_POINT_FEATURE = null;
+
+  /** The map context of the displayed layer. */
+  protected MapContext mapContext = null;
+
+  /** Contains the additional attributes for new FeatureCollections. */
+  protected FeatureType additionalAttr = null;
+  /** Contains the {@link InputOption} to specify the additional
+   *  attribute values.  */
+  protected FeatureInputOption attrInputOption = null;
+
+  /** The map context where the edited layers are displayed. This
+   *  context is displayed on top of the other layers. */
+  protected MapContext editorMapContext = null;
+  /** The renderer the edited layers are rendered with. */
+  protected GTRenderer editorRenderer = null;
+  /** Holds the {@link Style styles} to display edited layers. */
+  protected Map<GeometryForm,Style> editorStyles = null;
+  /** Holds the operation the editor currently performs. */
+  protected EditorMode editorMode = null;
+
+  /** Holds the {@link FeatureType} of the edited layer. */
+  protected FeatureType editorFeatureType = null;
+  /** Holds the kind of geometry of the edited layer. */
+  protected GeometryForm editorGeometryForm = null;
+  /** Holds the {@link FeatureCollection} of the edited layer. */
+  protected DefaultFeatureCollection editorFeatureCollection = null;
+  /** Holds the edited layer. */
+  protected MapLayer editorLayer = null;
+
+  /** Holds the {@link FeatureType} of the new segment (incomplete Feature)
+   *  displayed as line. */
+  protected FeatureType segmLineFeatureType = null;
+  /** Holds the {@link FeatureCollection} which holds the new segment
+   *  (incomplete Feature) displayed as line. */
+  protected DefaultFeatureCollection segmLineFeatureCollection = null;
+  /** Holds the layer, the new segment (incomplete Feature) is displayed in
+   *  as line. */
+  protected MapLayer segmLineLayer = null;
+
+  /** Holds the {@link FeatureType} of the new segment (incomplete Feature)
+   *  displayed as points. */
+  protected FeatureType segmPointFeatureType = null;
+  /** Holds the {@link FeatureCollection} which holds the new segment
+   *  (incomplete Feature) displayed as points. */
+  protected DefaultFeatureCollection segmPointFeatureCollection = null;
+  /** Holds the layer, the new segment (incomplete Feature) is displayed in
+   *  as points. */
+  protected MapLayer segmPointLayer = null;
+
+
+  /** Holds the points of the edited segment (incomplete Feature) which
+   *  can be undone. */
+  protected Stack<Coordinate> segmUndoPoints = new Stack<Coordinate>();
+  /** Holds the undone points of the edited segment (incomplete Feature) which
+   *  can be redone. */
+  protected Stack<Coordinate> segmRedoPoints = new Stack<Coordinate>();
+  /** Holds the points of former segments (complete Features) which
+   *  can be undone. */
+  protected Stack<Stack<Coordinate>> globalUndoPoints = new Stack<Stack<Coordinate>>();
+  /** Holds the undone points of former segments (complete Features) which
+   *  can be redone. */
+  protected Stack<Stack<Coordinate>> globalRedoPoints = new Stack<Stack<Coordinate>>();
+  /** Holds the former segments (complete Features) which can be undone. */
+  protected Stack<Feature> globalUndoFeatures = new Stack<Feature>();
+  /** Holds the undone segments (complete Features) which can be redone. */
+  protected Stack<Feature> globalRedoFeatures = new Stack<Feature>();
+
+  /**
+   * Creates a new {@code GeoEditorPane}.
+   */
+  public JEditorPane() {
+    this( new BorderLayout(),
+          true,
+          new TransitionShapefileRenderer(),
+          new DefaultMapContext(DefaultGeographicCRS.WGS84)
+    );
+  }
+
+  /**
+   * Creates a new {@code GeoEditorPane}. This constructor provides the possibility
+   * to use alternative implementations of the internal components.
+   * <b>The specified parameter all can be {@code null}! In this case
+   * the respective default component is used.</b>
+   */
+  public JEditorPane(LayoutManager layout, boolean isDoubleBuffered, GTRenderer renderer, MapContext context) {
+    super(layout,isDoubleBuffered,renderer,context);
+    this.mapContext = getContext();
+    // initalize the editor styles
+    this.editorStyles = new HashMap<GeometryForm, Style>();
+    for (GeometryForm geomForm : GeometryForm.values())
+      this.setEditorStyle(geomForm, null);
+
+    // no standard action on left mouse button, instead: adding points
+    setState( NONE );
+    setWindowSelectionState( ZOOM_IN );
+    // special map context for the editor layers, so the
+    // editor layers are not shown in "normal" layer list
+    this.editorRenderer   = new TransitionShapefileRenderer();
+    this.editorMapContext = new DefaultMapContext( mapContext.getCoordinateReferenceSystem() );
+    // listen to CRS/Area changes on the "normal" Context to
+    // synchronize the editor context
+    this.mapContext.addMapBoundsListener( new MapContextSynchronizer(editorMapContext) );
+
+    // create the input option to specify additional attribute values
+    attrInputOption = new FeatureInputOption(null,true,(Feature)null);
+  }
+
+  /**
+   * After the actions of the super method, this method paints the
+   * special editor layers in {@link #editorMapContext}.
+   */
+  protected void paintComponent(Graphics g) {
+    resetEditorLayerVisibility();
+    super.paintComponent(g);
+    Rectangle r = getBounds();
+    Rectangle dr = new Rectangle(r.width, r.height);
+    editorRenderer.setContext(editorMapContext);
+    editorRenderer.paint((Graphics2D) g, dr, mapArea);
+  }
+
+  /**
+   * Ignores the actions of the super class for left-clicks.
+   * Instead this method reacts according to the current
+   * editor mode.
+   */
+  public void mouseClicked(MouseEvent e) {
+    Point2D geoCoord = getTransform().transform(e.getPoint(), null);
+    // Zunaechst Modus auf NULL pruefen, da ansonsten
+    // NullPointerException in switch-Statement
+    if ( editorMode == null )
+      return;
+
+    switch( editorMode ) {
+      case New_Point:
+      case New_Line:
+      case New_Polygon: addSegment( new Coordinate(geoCoord.getX(), geoCoord.getY()) );
+                        break;
+    }
+  }
+
+  //**********************************************************************
+  //***** General public methods
+  //**********************************************************************
+
+  /**
+   * Checks, whether a layer is edited.
+   */
+  public boolean isEditorEnabled() {
+    return editorMode != null;
+  }
+
+  /**
+   * Sets the style for edited layers.
+   * @param geomForm kind of layers the style is set for
+   * @param style a Style (if {@code null} a default style is set, so
+   *              {@link #getEditorStyle(GeometryForm)} never returns null)
+   */
+  public void setEditorStyle(GeometryForm geomForm, Style style) {
+    // If no style is specified, set a default style
+    if ( style == null )
+      switch ( geomForm ) {
+        case POINT:   style = DEFAULT_POINT_STYLE; break;
+        case LINE:    style = DEFAULT_LINE_STYLE; break;
+        case POLYGON: style = DEFAULT_POLYGON_STYLE; break;
+      }
+
+    // Set the style
+    editorStyles.put(geomForm, style);
+
+    // Apply the style also to the current edited layer
+    if ( editorLayer != null && FeatureUtil.getGeometryForm(editorLayer) == geomForm )
+      editorLayer.setStyle(style);
+    if ( segmLineLayer != null && FeatureUtil.getGeometryForm(segmLineLayer) == geomForm )
+      segmLineLayer.setStyle(style);
+    if ( segmPointLayer != null && FeatureUtil.getGeometryForm(segmPointLayer) == geomForm )
+      segmPointLayer.setStyle(style);
+  }
+
+  /**
+   * Returns the style for edited layers.
+   * @param geomForm type of layers the style is returned for
+   */
+  public Style getEditorStyle(GeometryForm geomForm) {
+    return this.editorStyles.get(geomForm);
+  }
+
+  /**
+   * Returns the style for the current edited layer.
+   */
+  public Style getEditorStyle() {
+    if ( editorGeometryForm == null )
+      return null;
+    return this.editorStyles.get(editorGeometryForm);
+  }
+
+  /**
+   * Sets the additional attributes for new FeatureCollections (besides
+   * the geometric attribute, which is added automatically).
+   * @param fType defines the attributes (If {@code null}, new FeatureCollections
+   *              only contain the geometric attribute)
+   */
+  public void setAdditionalAttributes(FeatureType fType) {
+    this.additionalAttr = fType;
+  }
+
+  /**
+   * Returns the additional attributes for new FeatureCollections (besides
+   * the geometric attribute, which is added automatically).
+   */
+  public FeatureType getAdditionalAttributes() {
+    return this.additionalAttr;
+  }
+
+  /**
+   * Returns the current editor mode.
+   */
+  public EditorMode getEditorMode() {
+    return this.editorMode;
+  }
+
+  /**
+   * Returns the edited layer.
+   */
+  public MapLayer getEditorLayer() {
+    return this.editorLayer;
+  }
+
+  /**
+   * Returns the {@link FeatureCollection} of the edited layer.
+   */
+  public FeatureCollection getEditorFeatureCollection() {
+    return this.editorFeatureCollection;
+  }
+
+  //**********************************************************************
+  //*****  Public Methods controlling the editor operations
+  //**********************************************************************
+
+  /**
+   * Starts a new layer.
+   * @param mode type of layer
+   * @param layerTitle Title for the new layer
+   * @exception UnsupportedOperationException if no map area is defined yet
+   */
+  public void startEditing(EditorMode mode, String layerTitle) {
+    // to create a new layer, first an existing layer must be
+    // displayed, so that a CRS and geo-position is available
+    // for the new layer
+    if ( getMapArea() == null )
+      throw new UnsupportedOperationException( GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.gui.JEditorPane.Err.MissingMap") );
+    // cancel active editings
+    cancelEditing();
+    editorMode = mode;
+
+    // Create new Layers
+    initEditorFeatureCollection(layerTitle);
+    initSegmentFeatureCollection();
+    editorMapContext.addLayer(0,editorLayer);
+    fireMapPaneEvent( new LayerEditStartedEvent(this,editorLayer,this) );
+  }
+
+  /**
+   * Called when the mouse is clicked on map during creating a new layer.
+   * @param coord World coordinates of click position
+   * @param refresh indicates whether the visualisation will be refreshed
+   * @param aClearRedo indicates whether the REDO-Stack is cleared (normally {@code true},
+   *                   but {@code false} during REDO operation!)
+   */
+  protected void addSegment(Coordinate coord, boolean refresh, boolean clearRedo) {
+    if ( editorMode != EditorMode.New_Point &&
+         editorMode != EditorMode.New_Line &&
+         editorMode != EditorMode.New_Polygon )
+      return;
+
+    // store the new point for undoing
+    segmUndoPoints.push(coord);
+    // delete all former redo possibilities
+    if ( clearRedo )
+      segmRedoPoints.clear();
+    // recreate the segment FeatureCollection to show the extended line
+    generateSegmentFeatureCollection();
+
+    // finish the feature automatically
+    // - when editing points, because there are no segments for point layer,
+    //   because every point is a new feature
+    // - when editing polygons and reaching the start point
+    if ( editorGeometryForm == GeometryForm.POINT ||
+         editorGeometryForm == GeometryForm.POLYGON && segmUndoPoints.size() > 1 && segmUndoPoints.lastElement().equals(segmUndoPoints.firstElement()) )
+      finishFeature(refresh, clearRedo); // refresh is done by finishFeature()
+    else
+      if ( refresh )
+        refresh();
+  }
+
+  /**
+   * Called when the mouse is clicked on map during creating a new layer.
+   * @param coord World coordinates of click position
+   */
+  protected void addSegment(Coordinate coord) {
+    addSegment(coord, true, true);
+  }
+
+  /**
+   * Finishes the editing of the current segment (Feature).
+   * If no editing operation is currently in progress, this method does nothing.
+   * @param refresh indicates whether the visualisation will be refreshed
+   * @param aClearRedo indicates whether the REDO-Stack is cleared (normally {@code true},
+   *                   but {@code false} during REDO operation!)
+   * @exception UnsupportedOperationException if a line or polygon feature can not
+   *            be finished because of less specified points
+   */
+  protected void finishFeature(boolean refresh, boolean clearRedo) {
+    if ( editorMode == null )
+      return;
+
+    if ( editorGeometryForm == GeometryForm.LINE && segmUndoPoints.size() < 2 )
+      throw new UnsupportedOperationException( GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.gui.JEditorPane.Err.Line.LessPoints") );
+    if ( editorGeometryForm == GeometryForm.POLYGON && segmUndoPoints.size() < 3 )
+      throw new UnsupportedOperationException( GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.gui.JEditorPane.Err.Polygon.LessPoints") );
+
+    // close a polygon automatically
+    if ( editorGeometryForm == GeometryForm.POLYGON &&
+        !segmUndoPoints.lastElement().equals(segmUndoPoints.firstElement()) ) {
+      addSegment( segmUndoPoints.firstElement(), refresh, clearRedo );
+      return; // !!!! finishFeature(.) is called again by addSegment(..) !!!!
+    }
+    // create a new Feature from the segment points
+    Feature feature = createFeature();
+    if ( feature == null )
+      return;
+    fireMapPaneEvent( new FeatureModifiedEvent(this,editorLayer,feature,this) );
+
+    // update the global undo
+    globalUndoPoints.push( segmUndoPoints );
+    globalUndoFeatures.push( feature );
+    editorFeatureCollection.add( feature );
+
+    // after finishing a Feature, a new segment is started
+    segmUndoPoints = new Stack<Coordinate>();
+    if ( clearRedo )
+      segmRedoPoints = globalRedoPoints.isEmpty() ? new Stack<Coordinate>() : globalRedoPoints.pop();
+    initSegmentFeatureCollection();
+    // refresh the display
+    if ( refresh )
+      refresh();
+  }
+
+  /**
+   * Finishes the editing of the current segment (Feature).
+   * If no editing operation is currently in progress, this method does nothing.
+   */
+  public void finishFeature() {
+    finishFeature(true, true);
+  }
+
+  /**
+   * Finishes the current editing operation. After that no more operations
+   * on this layer can be performed.
+   * As long as no other editing operation is started, the edited (new) layer is
+   * available by {@link #getEditorLayer()} and {@link #getEditorFeatureCollection()}.
+   * If no editing operation is currently in progress, this method does nothing.
+   */
+  public void finishEditing() {
+    if ( editorMode == null )
+      return;
+
+    // if current segment is not closed, finish it automatically
+    if ( !segmUndoPoints.isEmpty() )
+      finishFeature();
+    initUndoRedo();
+
+    // move the edited layer to the "real" MapContext
+    editorMapContext.removeLayer(editorLayer);
+    if ( mapContext.indexOf(editorLayer) < 0 ) {
+      mapContext.addLayer(editorLayer);
+      editorLayer.setVisible(true);
+    }
+    fireMapPaneEvent( new LayerEditFinishedEvent(this,editorLayer,this) );
+
+    // initialize the editing variables
+    editorMode = null;
+    editorLayer = null;
+    editorFeatureCollection = null;
+    editorGeometryForm = null;
+
+    // refresh the display
+    refresh();
+  }
+
+  /**
+   * Cancels the current edititing operation. The edited layer is removed.
+   */
+  public void cancelEditing() {
+    if ( editorLayer != null )
+      this.editorMapContext.removeLayer( editorLayer );
+    if ( editorFeatureCollection != null ) {
+      if ( mapContext.indexOf(editorLayer) < 0 ) {
+        // Layer was a new one, so clear it completly
+        editorFeatureCollection.clear();
+        initUndoRedo();
+        fireMapPaneEvent( new LayerEditCanceledEvent(this,null,this) );
+      } else {
+        // Layer was an existing one, so undo all editing operations
+        undoAll();
+        initUndoRedo();
+        fireMapPaneEvent( new LayerEditFinishedEvent(this,editorLayer,this) );
+      }
+    }
+    if ( segmLineFeatureCollection != null )
+      segmLineFeatureCollection.clear();
+    if ( segmPointFeatureCollection != null )
+      segmPointFeatureCollection.clear();
+
+    // initialize the editing variables
+    editorMode = null;
+    editorLayer = null;
+    editorFeatureCollection = null;
+    editorGeometryForm = null;
+
+    // refresh the display
+    refresh();
+  }
+
+  /**
+   * Makes previously made editing actions undone.
+   * @param count count of operations made undone
+   */
+  public void undoEditing(int count) {
+    for (int i=0; i<count; i++)
+    {
+      if ( segmUndoPoints.isEmpty() ) {
+        if ( globalUndoPoints.isEmpty() )
+          // No more undo operations available
+          break;
+        else {
+          segmUndoPoints = globalUndoPoints.pop();
+          editorFeatureCollection.remove( globalUndoFeatures.peek() );
+
+          globalRedoFeatures.push( globalUndoFeatures.pop() );
+          if ( !segmRedoPoints.isEmpty() )
+            globalRedoPoints.push( segmRedoPoints );
+          segmRedoPoints = new Stack<Coordinate>();
+
+          // On lines the last point and finish feature operation
+          // are separated, so they also must be undone
+          // separately.
+          if ( editorGeometryForm == GeometryForm.LINE ) {
+            generateSegmentFeatureCollection();
+            continue;
+          }
+        }
+      }
+      segmRedoPoints.push( segmUndoPoints.pop() );
+      generateSegmentFeatureCollection();
+    }
+    refresh();
+  }
+
+  /**
+   * Makes the last made editing action undone.
+   */
+  public void undoEditing() {
+    undoEditing(1);
+  }
+
+  /**
+   * Makes all made editing action undone.
+   */
+  public void undoAll() {
+    undoEditing( Integer.MAX_VALUE );
+  }
+
+  /**
+   * Checks wheater a undo operation can be performed.
+   */
+  public boolean isUndoPossible() {
+    return !segmUndoPoints.isEmpty() || !globalUndoPoints.isEmpty();
+  }
+
+  /**
+   * Restores previous undone editing actions.
+   * @param count count of redo operations
+   */
+  public void redoEditing(int count) {
+    for (int i=0; i<count; i++)
+    {
+      if ( segmRedoPoints.isEmpty() ) {
+        if ( globalRedoPoints.isEmpty() )
+          // No more redo operations available
+          break;
+        else {
+          // Lines must be finished when all segment redo operations
+          // are redone; Points and Polygons must not, because they
+          // were already closed on last addSegment(.) (closing point
+          // of polygon is also a part of the redo stack!)
+          if ( editorGeometryForm == GeometryForm.LINE )
+            finishFeature(false, false);
+          segmRedoPoints = globalRedoPoints.pop();
+        }
+      }
+      addSegment( segmRedoPoints.pop(), false, false );
+    }
+    refresh();
+  }
+
+  /**
+   * Restores the last undone editing action.
+   */
+  public void redoEditing() {
+    redoEditing(1);
+  }
+
+  /**
+   * Checks wheater a redo operation can be performed.
+   */
+  public boolean isRedoPossible() {
+    // Redo possible if
+    // - some operations of the current segment can be redone
+    // - some operations of former segments can be redone
+    return !segmRedoPoints.isEmpty() || !globalRedoPoints.isEmpty();
+  }
+
+  //**********************************************************************
+  //*****  Helper methods for the editor operations
+  //**********************************************************************
+  /**
+   * Sets {@link #editorFeatureCollection} and {@link #editorLayer} to completely
+   * new instances.
+   * @param title title for the new layer
+   */
+  protected void initUndoRedo() {
+    // initialize the Undo/Redo-Stacks
+    for ( Stack s : globalRedoPoints ) s.clear();
+    for ( Stack s : globalUndoPoints ) s.clear();
+    globalRedoPoints.clear();
+    globalUndoPoints.clear();
+    globalRedoFeatures.clear();
+    globalUndoFeatures.clear();
+    segmRedoPoints.clear();
+    segmUndoPoints.clear();
+  }
+
+  /**
+   * Sets {@link #editorFeatureCollection} and {@link #editorLayer} to completely
+   * new instances.
+   * @param title title for the new layer
+   */
+  protected void initEditorFeatureCollection(String title) {
+    // create the new layer
+    editorFeatureCollection = (DefaultFeatureCollection)DefaultFeatureCollections.newCollection(title);
+    editorFeatureType       = createFeatureType(editorMode, getAdditionalAttributes());
+    DUMMY_EDITOR_FEATURE    = createDummyFeature(editorFeatureType);
+    editorFeatureCollection.add(DUMMY_EDITOR_FEATURE);
+    editorGeometryForm      = FeatureUtil.getGeometryForm(editorFeatureCollection);
+    editorLayer             = new DefaultMapLayer(editorFeatureCollection,getEditorStyle(editorGeometryForm));
+    editorLayer.setTitle(title);
+  }
+
+  /**
+   * Clears the {@link FeatureCollection} used to handle the current
+   * edited segment.
+   */
+  protected void initSegmentFeatureCollection() {
+    // initialize the segment to start a new feature
+    if ( segmLineFeatureCollection == null ) {
+      // initialize the objects used to display the
+      // current segment as line
+      segmLineFeatureCollection = (DefaultFeatureCollection)DefaultFeatureCollections.newCollection("SegmentAsLine");
+      segmLineFeatureType       = createFeatureType(LineString.class, null);
+      DUMMY_LINE_FEATURE        = createDummyFeature(segmLineFeatureType);
+      segmLineFeatureCollection.add(DUMMY_LINE_FEATURE);
+      segmLineLayer             = new DefaultMapLayer(segmLineFeatureCollection,getEditorStyle(GeometryForm.LINE));
+      segmLineLayer.setTitle("Line layer for current segment");
+      editorMapContext.addLayer(segmLineLayer);
+      // initialize the objects used to display the
+      // current segment as points
+      segmPointFeatureCollection = (DefaultFeatureCollection)DefaultFeatureCollections.newCollection("SegmentAsPoints");
+      segmPointFeatureType       = createFeatureType(MultiPoint.class, null);
+      DUMMY_POINT_FEATURE        = createDummyFeature(segmPointFeatureType);
+      segmPointFeatureCollection.add(DUMMY_POINT_FEATURE);
+      segmPointLayer             = new DefaultMapLayer(segmPointFeatureCollection,getEditorStyle(GeometryForm.POINT));
+      segmPointLayer.setTitle("Point layer for current segment");
+      editorMapContext.addLayer(segmPointLayer);
+    } else {
+      segmLineFeatureCollection.clear();
+      segmPointFeatureCollection.clear();
+    }
+  }
+
+  /**
+   * Creates a new segment Feature from the currently selected points.
+   */
+  protected void generateSegmentFeatureCollection() {
+    initSegmentFeatureCollection();
+    // show the segment as single points
+    Feature segmPointFeature = createSegmentPointFeature();
+    if ( segmPointFeature != null )
+      segmPointFeatureCollection.add( segmPointFeature );
+    // show the segment as a line
+    Feature segmLineFeature = createSegmentLineFeature();
+    if ( segmLineFeature != null )
+      segmLineFeatureCollection.add( segmLineFeature );
+    // Fire event even if no (real) feature is created!
+    fireMapPaneEvent( new FeatureModifiedEvent(this,segmLineLayer,segmLineFeature,this) );
+  }
+
+  /**
+   * Creates a new {@link Feature Line-Feature} from the currently selected
+   * segment points.
+   */
+  protected Feature createSegmentLineFeature() {
+    // Line can only be created with at least 2 points
+    // For point layer the segment is not shown
+    if ( segmUndoPoints.size() < 2 ||
+         editorGeometryForm == GeometryForm.POINT )
+      return null;
+
+    Coordinate[] coord      = segmUndoPoints.toArray(new Coordinate[0]);
+    LineString   lineString = createGeometryFromPoints(LineString.class, coord);
+    try {
+      return segmLineFeatureType.create( new Object[] {lineString} );
+    } catch (Exception e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  /**
+   * Creates a new {@link Feature MultiPoint-Feature} from the currently selected
+   * segment points.
+   */
+  protected Feature createSegmentPointFeature() {
+    // Point can only be created with at least 1 point
+    // For point layer the segment is not shown
+    if ( segmUndoPoints.size() < 1 ||
+         editorGeometryForm == GeometryForm.POINT )
+      return null;
+
+    Coordinate[] coord      = segmUndoPoints.toArray(new Coordinate[0]);
+    MultiPoint   multiPoint = createGeometryFromPoints(MultiPoint.class, coord);
+    try {
+      return segmPointFeatureType.create( new Object[] {multiPoint} );
+    } catch (Exception e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  /**
+   * Creates a new Feature from the currently selected points. The non-geometric
+   * attributes are set to default values.
+   */
+  private Feature createFeature() {
+    Coordinate[] coord   = segmUndoPoints.toArray(new Coordinate[0]);
+    Feature      feature = null;
+    try {
+      // if a feature was undone previously use this as
+      // default for the new feature
+      if ( !globalRedoFeatures.isEmpty() )
+        feature = globalRedoFeatures.pop();
+      else {
+        // generate default attribute values
+        Object[] attr = FeatureUtil.getDefaultAttributeValues(editorFeatureType);
+        // replace default attribute values with auto generate
+        // values (for all registered attributes)
+        for (int i=0; i<attr.length; i++) {
+          AttributeType aType = editorFeatureType.getAttributeType(i);
+          if ( FeatureUtil.getAutoValueGenerator(aType) != null )
+            attr[i] = FeatureUtil.getNextAutoValue(aType);
+        }
+        // create new feature
+        feature = editorFeatureType.create(attr);
+      }
+      feature.setDefaultGeometry(
+          createGeometryFromPoints(getGeometryType(editorMode), coord )
+      );
+
+      if ( feature.getNumberOfAttributes() > 1 ) {
+        attrInputOption.setValue(feature);
+        Object[] value = MultipleOptionPane.showMultipleInputDialog(
+                            this,
+                            GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.gui.JEditorToolBar.NewFeature.title"),
+                            attrInputOption
+        );
+        if ( value == null )
+          return null;
+      }
+      return feature;
+    } catch (Exception e) {
+      throw new RuntimeException(e);
+    }
+
+  }
+
+
+  //**********************************************************************
+  //*****  Helper methods to deal with geometries
+  //**********************************************************************
+  /**
+   * Determines the geometry type to deal with according to the
+   * editor mode.
+   * @param mode editor mode
+   */
+  private static Class<? extends Geometry> getGeometryType(EditorMode mode) {
+    switch( mode ) {
+      case New_Point:   return Point.class;
+      case New_Line:    return LineString.class;
+      case New_Polygon: return Polygon.class;
+    }
+    return null;
+  }
+
+  /**
+   * Creates a geometry (point, linestring/ring, polygon) from a set of points. If
+   * no points are specified ({@code null}), a default geometry is created.
+   * @param gtype type of geometry
+   * @param coord set of points (can be {@code null})
+   */
+  private static <G extends Geometry> G createGeometryFromPoints(Class<G> gtype, Coordinate[] coord) {
+    // Point
+    if ( gtype.isAssignableFrom( com.vividsolutions.jts.geom.Point.class ) ) {
+      if ( coord == null )
+        coord = new Coordinate[] { new Coordinate() };
+      return (G)FeatureUtil.GEOMETRY_FACTORY.createPoint( coord[0] );
+    }
+    // MultiPoint
+    if ( gtype.isAssignableFrom( com.vividsolutions.jts.geom.MultiPoint.class ) ) {
+      if ( coord == null )
+        coord = new Coordinate[] { new Coordinate() };
+      return (G)FeatureUtil.GEOMETRY_FACTORY.createMultiPoint( coord );
+    }
+    // LineString
+    if ( gtype.isAssignableFrom( com.vividsolutions.jts.geom.LineString.class ) ) {
+      if ( coord != null && coord.length > 2 && coord[0].equals(coord[coord.length-1]) )
+        return (G)FeatureUtil.GEOMETRY_FACTORY.createLinearRing(coord);
+      return (G)FeatureUtil.GEOMETRY_FACTORY.createLineString(coord);
+    }
+    // Polygon
+    if ( gtype.isAssignableFrom( com.vividsolutions.jts.geom.Polygon.class ) ) {
+      LinearRing shell = null;
+      if ( coord != null && coord.length > 2 && coord[0].equals(coord[coord.length-1]) )
+        shell = FeatureUtil.GEOMETRY_FACTORY.createLinearRing(coord);
+      return (G)FeatureUtil.GEOMETRY_FACTORY.createPolygon(shell,null);
+    }
+
+    throw new UnsupportedOperationException("Can not create geometry for "+gtype.getName());
+  }
+
+  /**
+   * Extends a feature type with a default geometry attribute.
+   * @param gtype default geometry of the new feature type
+   * @param ftype a feature type which is extended (can be {@code null})
+   */
+  private FeatureType createFeatureType(Class<? extends Geometry> gtype, FeatureType ftype) {
+    GeometryAttributeType geomAttrType = new GeometricAttributeType(
+        GEOMETRY_ATTR,
+        gtype,
+        false,
+        createGeometryFromPoints(gtype,null),
+        mapContext.getCoordinateReferenceSystem(),
+        null
+    );
+    String ftypeName           = ftype != null ? ftype.getTypeName() : gtype.getSimpleName()+"_feature";
+    FeatureTypeBuilder builder = FeatureTypeBuilder.newInstance(ftypeName);
+    builder.setDefaultGeometry( geomAttrType );
+    if ( ftype != null )
+      builder.addTypes( ftype.getAttributeTypes() );
+    try {
+      return builder.getFeatureType();
+    } catch ( SchemaException err ) {
+      throw new RuntimeException(err);
+    }
+  }
+
+  /**
+   * Extends a feature type with a default geometry attribute.
+   * @param mode  specifies the the default geometry used for the feature type
+   * @param ftype a feature type which is extended (can be {@code null})
+   */
+  private FeatureType createFeatureType(EditorMode mode, FeatureType ftype) {
+    Class<? extends Geometry> gtype = null;
+    switch( mode ) {
+      case New_Point:   gtype = Point.class; break;
+      case New_Line:    gtype = LineString.class; break;
+      case New_Polygon: gtype = Polygon.class; break;
+    }
+    return createFeatureType(gtype,ftype);
+  }
+
+  /**
+   * Creates a feature with default values for a given feature type.
+   * @param ftype a feature type
+   */
+  private static Feature createDummyFeature(FeatureType ftype) {
+    try {
+      return ftype.create( FeatureUtil.getDefaultAttributeValues(ftype) );
+    } catch (Exception e) {
+      throw new RuntimeException(e);
+    }
+  }
+
+  /**
+   * Checks, whether the editor layer is empty. If it is, a dummy feature is inserted
+   * because the StreamingRenderer can not handle empty Feature-Layers yet
+   * (also if the layer is hidden!).
+   * At the moment, the first a feature is added, the dummy feature is removed, so
+   * is is not displayed any time.
+   */
+  private void resetEditorLayerVisibility() {
+    // if layer is empty, insert a Dummy-Feature (and hide the
+    // layer) because the StreamingRenderer can not handle empty
+    // Feature-Layers yet
+    if ( segmLineFeatureCollection != null && segmLineFeatureCollection.size() == 0 )
+      segmLineFeatureCollection.add( DUMMY_LINE_FEATURE );
+    if ( segmPointFeatureCollection != null && segmPointFeatureCollection.size() == 0 )
+      segmPointFeatureCollection.add( DUMMY_POINT_FEATURE );
+    if ( editorFeatureCollection != null && editorFeatureCollection.size() == 0 )
+      editorFeatureCollection.add( DUMMY_EDITOR_FEATURE );
+
+    // if the layer is not empty anymore, remove the Dummy-Feature, so
+    // it is not displayed
+    if ( segmLineFeatureCollection != null && segmLineFeatureCollection.size() == 2 )
+      segmLineFeatureCollection.remove( DUMMY_LINE_FEATURE );
+    if ( segmPointFeatureCollection != null && segmPointFeatureCollection.size() == 2 )
+      segmPointFeatureCollection.remove( DUMMY_POINT_FEATURE );
+    if ( editorFeatureCollection != null && editorFeatureCollection.size() == 2 )
+      editorFeatureCollection.remove( DUMMY_EDITOR_FEATURE );
+
+    // hide the editor layer if it only contains the dummy feature
+    if ( editorLayer != null )
+      editorLayer.setVisible(editorFeatureCollection.size() > 1 || !editorFeatureCollection.contains(DUMMY_EDITOR_FEATURE));
+    if ( segmLineLayer != null )
+      segmLineLayer.setVisible(segmLineFeatureCollection.size() > 1 || !segmLineFeatureCollection.contains(DUMMY_LINE_FEATURE));
+    if ( segmPointLayer != null )
+      segmPointLayer.setVisible(segmPointFeatureCollection.size() > 1 || !segmPointFeatureCollection.contains(DUMMY_POINT_FEATURE));
+  }
+
+}

Modified: trunk/src/schmitzm/geotools/gui/JEditorToolBar.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/JEditorToolBar.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/JEditorToolBar.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,503 +1,532 @@
-package schmitzm.geotools.gui;
-
-import java.awt.event.ActionEvent;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-import javax.swing.AbstractAction;
-import javax.swing.AbstractButton;
-import javax.swing.Icon;
-import javax.swing.ImageIcon;
-import javax.swing.JButton;
-import javax.swing.JToolBar;
-
-import org.apache.log4j.Logger;
-import org.geotools.feature.FeatureType;
-
-import schmitzm.geotools.gui.JEditorPane.EditorMode;
-import schmitzm.geotools.map.event.JEditorPaneEvent;
-import schmitzm.geotools.map.event.JMapPaneEvent;
-import schmitzm.geotools.map.event.JMapPaneListener;
-import schmitzm.geotools.map.event.LayerEditCanceledEvent;
-import schmitzm.geotools.map.event.LayerEditFinishedEvent;
-import schmitzm.swing.ExceptionDialog;
-import schmitzm.swing.ManualInputOption;
-import schmitzm.swing.MultipleOptionPane;
-import schmitzm.swing.SelectionInputOption;
-
-/**
- * A toolbar to control the operations of a {@link JEditorPane}.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- */
-public class JEditorToolBar extends JToolBar {
-	private static final Logger LOGGER = Logger.getLogger(JEditorToolBar.class.getName());
-	/** Constant for the tool "New layer" (10). */
-	public static final int LAYER_NEW = 10;
-    /** Constant for the tool "Save layer" (20). */
-    public static final int LAYER_SAVE = 20;
-    /** Constant for the tool "Cancel layer" (30). */
-    public static final int LAYER_CANCEL = 30;
-    /** Constant for the tool "Undo all editor actions" (100). */
-    public static final int EDIT_CLEAR = 100;
-	/** Constant for the tool "Undo last editor action" (110). */
-	public static final int EDIT_UNDO = 110;
-	/** Constant for the tool "Redo last undone editor action" (120). */
-	public static final int EDIT_REDO = 120;
-    /** Constant for the tool "Finish current segment" (130). */
-    public static final int EDIT_FINISH = 130;
-
-    /** Holds the action buttons of the bar. */
-    protected SortedMap<Integer, JButton> actionButtons = null;
-
-	/** Holds the {@link JEditorPane} this tool bar controls. */
-	protected JEditorPane editorPane = null;
-	
-	/** Holds the listener, that reacts on editor actions. */
-	protected JMapPaneListener mapPaneListener = null;
-
-    /**
-     * Creates a new toolbar. Notice: This toolbar does nothing
-     * until {@link #setMapPane(JEditorPane)} is called!
-     */
-    public JEditorToolBar() {
-      this(null);
-    }
-    
-    /**
-	 * Creates a new tool bar.
-	 * @param editorPane {@link JEditorPane} the tool bar controls
-	 */
-	public JEditorToolBar(JEditorPane editorPane) {
-	  super("Control the editor actions", JToolBar.HORIZONTAL);
-      this.actionButtons   = new TreeMap<Integer,JButton>();
-      // Create a Listener to sniff the zooms on the JMapPane
-      this.mapPaneListener = new JMapPaneListener() {
-          public void performMapPaneEvent(JMapPaneEvent e) {
-              if ( !(e instanceof JEditorPaneEvent) )
-                return;
-
-              // At the moment the layer editing is finished, the editor mode
-              // is not yet initialized. However for the button activation the
-              // mode NULL is essential in this case.
-              EditorMode mode = ((JEditorPaneEvent)e).getEditorMode();
-              if ( e instanceof LayerEditCanceledEvent ||
-                   e instanceof LayerEditFinishedEvent )
-                mode = null;
-              updateButtonActivation(mode);
-          }
-      };    
-     
-      setMapPane(editorPane);
-	  setFloatable(false);
-	  setRollover(true);
-	  
-	  init();
-	}
-	
-	/**
-	 * Sets the {@link JEditorPane} controlled by this tool bar.
-	 * @param editorPane {@link JEditorPane} to control (if {@code null} this
-	 *                   tool bar controls NOTHING!)
-	 */
-	public void setMapPane(JEditorPane editorPane) {
-	  // Remove listener from old MapPane
-	  if ( this.editorPane != null )
-	    this.editorPane.removeMapPaneListener( mapPaneListener );
-      this.editorPane = editorPane;
-      if ( this.editorPane != null && mapPaneListener != null )
-        this.editorPane.addMapPaneListener( mapPaneListener );
-	}
-	
-	/**
-	 * Calls {@link #initActions()} and then puts all action buttons
-	 * to the tool bar.
-	 */
-	protected void init() {
-	  initActions();
-	  initToolBar();
-	  updateButtonActivation(null);
-	}
-
-    /**
-     * Creates the action buttons and adds them to {@link #actionButtons}.
-     */
-    protected void initActions() {
-      // Action button to create a new layer
-      addAction( new EditorPaneToolBarAction(
-          LAYER_NEW,
-          this,
-          "button.layer.new",
-          new ImageIcon(JEditorPane.class.getResource("resource/icons/layer_new.png"))
-      ), false);
-
-      // Action button to finish a layer
-      addAction( new EditorPaneToolBarAction(
-          LAYER_SAVE,
-          this,
-          "button.layer.save",
-          new ImageIcon(JEditorPane.class.getResource("resource/icons/layer_finish.png"))
-      ), false);
-
-      // Action button to cancel a layer
-      addAction( new EditorPaneToolBarAction(
-          LAYER_CANCEL,
-          this,
-          "button.layer.cancel",
-          new ImageIcon(JEditorPane.class.getResource("resource/icons/layer_cancel.png"))
-      ), false);
-
-      // Action button to undo all editing action
-      addAction( new EditorPaneToolBarAction(
-          EDIT_CLEAR,
-          this,
-          "button.edit.clear",
-          new ImageIcon(JEditorPane.class.getResource("resource/icons/edit_clear.png"))
-      ), false);
-
-      // Action button to undo a editing action
-      addAction( new EditorPaneToolBarAction(
-          EDIT_UNDO,
-          this,
-          "button.edit.undo",
-          new ImageIcon(JEditorPane.class.getResource("resource/icons/edit_undo.png"))
-      ), false);
-
-      // Action button to redo a undone editing action
-      addAction( new EditorPaneToolBarAction(
-          EDIT_REDO,
-          this,
-          "button.edit.redo",
-          new ImageIcon(JEditorPane.class.getResource("resource/icons/edit_redo.png"))
-      ), false);
-
-      // Action button to finish a feature
-      addAction( new EditorPaneToolBarAction(
-          EDIT_FINISH,
-          this,
-          "button.edit.finish",
-          new ImageIcon(JEditorPane.class.getResource("resource/icons/edit_finish.png"))
-      ), false);
-    }
-    
-    /**
-     * Clears the GUI of all components and adds all action buttons to the
-     * tool bar.
-     */
-    protected void initToolBar() {
-      setAlignmentY( 1f );
-      removeAll();
-//      // Separator to the left of the tool actions to start
-//      // the tool buttons with the map (not with the coordinate grid)
-//      Dimension dimension = new Dimension( 49,10);
-//      addSeparator(dimension);
-//      // Space between tool buttons and action buttons
-//      Dimension dimension2 = new Dimension( 10,10);
-//      this.addSeparator(dimension2);
-      // Action buttons
-      for (JButton b : actionButtons.values())
-        add(b);
-    }
-    
-
-    /**
-     * Performs the action of an action button.
-     * @param tool the action
-     * @param e    the event of the button
-     */
-	protected void performActionButton(int action, ActionEvent e) {
-      if ( editorPane == null )
-        return;
-      
-      try {
-        // Perform the action "New layer"
-        if ( action == LAYER_NEW )
-          createNewLayer();
-        // Perform the action "Finish layer"
-        if ( action == LAYER_SAVE )
-          editorPane.finishEditing();
-        // Perform the action "Cancel layer"
-        if ( action == LAYER_CANCEL )
-          editorPane.cancelEditing();
-  
-        // Perform the action "Finish feature"
-        if ( action == EDIT_FINISH )
-          editorPane.finishFeature();
-        // Perform the action "Undo editing"
-        if ( action == EDIT_UNDO )
-          editorPane.undoEditing();
-        // Perform the action "Redo editing"
-        if ( action == EDIT_REDO )
-          editorPane.redoEditing();
-        // Perform the action "Clear editing"
-        if ( action == EDIT_CLEAR )
-          editorPane.undoAll();
-      } catch (Exception err) {
-        ExceptionDialog.show(err);
-      }
-	}
-	
-	/**
-	 * Sets the enables/disables property for every toolbar button according 
-	 * to the current editor state. 
-	 * @param editorMode editor mode (because some events are fired BEFORE
-	 *                   the new mode is set)
-	 */
-	protected void updateButtonActivation(EditorMode editorMode) {
-	  if ( editorPane == null ) {
-	    setAllActionsEnabled(false, false);
-	    return;
-	  }
-      getButton( LAYER_NEW ).setEnabled( editorMode == null );
-	  getButton( LAYER_SAVE ).setEnabled( editorMode != null );
-      getButton( LAYER_CANCEL ).setEnabled( editorMode != null );
-      getButton( EDIT_UNDO ).setEnabled( editorPane.isUndoPossible() );
-      getButton( EDIT_REDO ).setEnabled( editorPane.isRedoPossible() );
-      getButton( EDIT_CLEAR ).setEnabled( editorPane.isUndoPossible() );
-      getButton( EDIT_FINISH ).setEnabled( editorMode != null && editorMode != EditorMode.New_Point );
-	}
-	
-	/**
-	 * Starts new layer.
-	 */
-	protected void createNewLayer() {
-	  // Ask layer type and name
-	  ManualInputOption.Text titleOption = new ManualInputOption.Text(
-	      getResourceString("NewLayer.layer.title"), true, getResourceString("NewLayer.layer.title.default")
-      );
-	  SelectionInputOption.Radio<JEditorPane.EditorMode> typeOption = new SelectionInputOption.Radio<JEditorPane.EditorMode>(
-          getResourceString("NewLayer.layer.type"),
-          true,
-          new JEditorPane.EditorMode[] { EditorMode.New_Point, EditorMode.New_Line, EditorMode.New_Polygon },
-          new String[] { getResourceString("NewLayer.layer.type.point"), getResourceString("NewLayer.layer.type.line"), getResourceString("NewLayer.layer.type.polygon") }
-	  );
-	  FeatureTypeInputOption ftOption = new FeatureTypeInputOption(
-	      getResourceString("NewLayer.ftype.title"),
-	      false
-	  ) {
-	        // Checks whether "the_geom" is used as attribute name
-	        // --> not allowed because JEditorPane uses this attribute
-	        //     for the default geometry of new layers
-    	    public boolean performIsInputValid() {
-    	      if ( super.performIsInputValid() ) {
-    	        FeatureType ft = inpTableModel.createFeatureType();
-    	        if ( ft.getAttributeType( JEditorPane.GEOMETRY_ATTR ) != null )
-    	          throw new UnsupportedOperationException(getResourceString("NewLayer.Err.GeomAttr",JEditorPane.GEOMETRY_ATTR));
-    	      }
-    	      return true;
-    	    }
-	  };
-	  Object[] value = MultipleOptionPane.showMultipleInputDialog(
-	      this,
-	      getResourceString("NewLayer.dialog.title"),
-	      titleOption,
-	      typeOption,
-	      ftOption
-	  );
-	  if ( value == null )
-	    return; // Dialog canceled
-	  editorPane.setAdditionalAttributes( ftOption.getValue() );
-	  editorPane.startEditing(
-	      (JEditorPane.EditorMode)value[1],
-	      (String)value[0]
-	  );
-	}
-
-    /**
-     * Adds an action to the tool bar. Does nothing if a tool or action with the
-     * specified ID already exists!
-     * @param buttonAction action for the button
-     * @param resetToolBar indicates whether the toolbar GUI is reset after adding
-     *                     the button (if adding several actions it useful only to
-     *                     reset the GUI for the last added tool) 
-     */
-    public void addAction(EditorPaneToolBarAction buttonAction, boolean resetToolBar) {
-      if ( isButtonIDUsed(buttonAction.getID()) ) {
-        LOGGER.warn("addAction(.) ignored because ID already used for tool or action: "+buttonAction.getID());
-        return;
-      }
-      JButton button = new JButton(buttonAction);
-      actionButtons.put( buttonAction.getID(), button );
-      if ( resetToolBar )
-        initToolBar();
-    }
-
-    /**
-     * Adds an action to the tool bar and resets the toolbar GUI.
-     * @param buttonAction action for the toggle button
-     */
-    public void addAction(EditorPaneToolBarAction buttonAction) {
-      addAction(buttonAction, true);
-    }
-    
-    /**
-     * Returns the button for a specific tool or action.
-     * @param id the constant for a tool
-     * @return a {@link JButton} if {@code id} specifies an {@linkplain #getActionButton(int) action button}
-     *         or {@link JToogleButton} if {@code id} specifies a {@linkplain #getToolButton(int) tool button}
-     */
-    public AbstractButton getButton(int id) {
-      AbstractButton button = actionButtons.get(id);
-      if ( button == null )
-        LOGGER.warn("Unknown action ID: "+id);
-      return button;
-    }
-
-    /**
-     * Returns the button for a specific action.
-     * @param action the constant an action 
-     */
-    public JButton getActionButton(int action) {
-      AbstractButton button = getButton(action);
-      if ( button != null && !(button instanceof JButton) ) {
-        LOGGER.warn("ID specifies no action: "+action);
-        button = null;
-      }
-      return (JButton)button; 
-
-    }
-
-    /**
-     * Sets whether an action is activated or not. The visible property
-     * of the button is not affected.
-     * @param id actionID
-     * @param enabled if {@code true} the action becomes available
-     */
-    public void setButtonEnabled(int id, boolean enabled) {
-      AbstractButton button = getButton(id);
-      if ( button == null )
-        return;
-      button.setEnabled( enabled );
-    }
-
-    /**
-     * Sets whether an action is activated or not.
-     * @param id actionID
-     * @param enabled if {@code true} the tool becomes available
-     * @param hideOnDisable if {@code true} the button is also hidden if
-     *                      {@code enabled} is {@code false}
-     */
-	public void setButtonEnabled(int id, boolean enabled, boolean hideOnDisable) {
-	  AbstractButton button = getButton(id);
-	  if ( button == null )
-	    return;
-	  button.setEnabled( enabled );
-	  // if button is enabled, it becomes visible anyway
-	  // if button is disabled and the "hide" option is set, it is also hidden 
-	  if ( enabled )
-	    button.setVisible( true );
-	  else
-	    button.setVisible( !hideOnDisable );
-	}
-
-    /**
-     * Checks whether a ID is already used for a tool or action.
-     * @param tool tool ID
-     */
-    public boolean isButtonIDUsed(int id) {
-      return actionButtons.get(id) != null;
-    }
-
-    /**
-     * Checks whether a tool is activated.
-     * @param tool tool ID
-     * @return {@code false} if an unknown ID is specified
-     */
-    public boolean isButtonEnabled(int id) {
-      AbstractButton button = getButton(id);
-      if ( button != null )
-        return button.isEnabled();
-      return false;
-    }
-
-    /**
-     * Sets the activation for all actions.
-     * @param enabled if {@code true} all actions becomes available
-     * @param hideOnDisable if {@code true} the buttons are also hidden if
-     *                      {@code enabled} is {@code false}
-     */
-    public void setAllActionsEnabled(boolean enabled, boolean hideOnDisable) {
-      for (int tool : actionButtons.keySet())
-        setButtonEnabled(tool,enabled,hideOnDisable);
-    }   
-    
-    /**
-     * Returns the maximum ID of actions. 
-     */
-    public int getMaxActionID() {
-      return actionButtons.lastKey();
-    }
-
-    /**
-     * Returns the minimum ID of actions. 
-     */
-    public int getMinActionID() {
-      return actionButtons.firstKey();
-    }
-    
-    protected static String getResourceString(String key, Object... params) {
-      return GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.gui.JEditorToolBar."+key,params);
-    }
-    
-    /**
-     * Extends the {@link AbstractAction} with maintaining an ID and
-     * the {@link JEditorToolBar} the action controls.
-     * Additionally this class automatically calls
-     * {@link JEditorToolBar#performActionButton(int, ActionEvent)}.
-     * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-     */
-    public static class EditorPaneToolBarAction extends AbstractAction {
-      /** The ID of the action */
-      protected int id = -1;
-      /** The tool bar, this action is made for. */
-      protected JEditorToolBar toolBar = null;
-
-      /**
-       * Creates a new action with a dummy description and no icon.
-       * @param id      unique ID for the action
-       * @param toolBar toolbar this action is made for
-       */
-      public EditorPaneToolBarAction(int id, JEditorToolBar toolBar) {
-        this(id,toolBar,""+id);
-      }
-
-      /**
-       * Creates a new action without an icon.
-       * @param id      unique ID for the action
-       * @param toolBar toolbar this action is made for
-       * @param name    description used for buttons or menus 
-       */
-      public EditorPaneToolBarAction(int id, JEditorToolBar toolBar, String name) {
-        this(id,toolBar,name,null);
-      }
-
-      /**
-       * Creates a new action.
-       * @param id      unique ID for the action
-       * @param toolBar toolbar this action is made for
-       * @param name    description used for buttons or menus 
-       * @param icon    icon used for buttons or menus 
-       */
-      public EditorPaneToolBarAction(int id, JEditorToolBar toolBar, String name, Icon icon) {
-        super("",icon);
-        this.id      = id;
-        this.toolBar = toolBar;
-        this.putValue(SHORT_DESCRIPTION, getResourceString(name));
-      }
-
-      /**
-       * Calls {@link JEditorToolBar#performActionButton(int, ActionEvent)}.
-       */
-      public void actionPerformed(ActionEvent e) {
-        if ( toolBar.actionButtons.get(id) != null )
-          toolBar.performActionButton(id, e);
-      }
-      
-      /**
-       * Returns the (unique) id of this action.
-       * @return
-       */
-      public int getID() {
-        return id;
-      }
-    }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.gui;
+
+import java.awt.event.ActionEvent;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import javax.swing.AbstractAction;
+import javax.swing.AbstractButton;
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JToolBar;
+
+import org.apache.log4j.Logger;
+import org.geotools.feature.FeatureType;
+
+import schmitzm.geotools.gui.JEditorPane.EditorMode;
+import schmitzm.geotools.map.event.JEditorPaneEvent;
+import schmitzm.geotools.map.event.JMapPaneEvent;
+import schmitzm.geotools.map.event.JMapPaneListener;
+import schmitzm.geotools.map.event.LayerEditCanceledEvent;
+import schmitzm.geotools.map.event.LayerEditFinishedEvent;
+import schmitzm.swing.ExceptionDialog;
+import schmitzm.swing.ManualInputOption;
+import schmitzm.swing.MultipleOptionPane;
+import schmitzm.swing.SelectionInputOption;
+
+/**
+ * A toolbar to control the operations of a {@link JEditorPane}.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ */
+public class JEditorToolBar extends JToolBar {
+	private static final Logger LOGGER = Logger.getLogger(JEditorToolBar.class.getName());
+	/** Constant for the tool "New layer" (10). */
+	public static final int LAYER_NEW = 10;
+    /** Constant for the tool "Save layer" (20). */
+    public static final int LAYER_SAVE = 20;
+    /** Constant for the tool "Cancel layer" (30). */
+    public static final int LAYER_CANCEL = 30;
+    /** Constant for the tool "Undo all editor actions" (100). */
+    public static final int EDIT_CLEAR = 100;
+	/** Constant for the tool "Undo last editor action" (110). */
+	public static final int EDIT_UNDO = 110;
+	/** Constant for the tool "Redo last undone editor action" (120). */
+	public static final int EDIT_REDO = 120;
+    /** Constant for the tool "Finish current segment" (130). */
+    public static final int EDIT_FINISH = 130;
+
+    /** Holds the action buttons of the bar. */
+    protected SortedMap<Integer, JButton> actionButtons = null;
+
+	/** Holds the {@link JEditorPane} this tool bar controls. */
+	protected JEditorPane editorPane = null;
+	
+	/** Holds the listener, that reacts on editor actions. */
+	protected JMapPaneListener mapPaneListener = null;
+
+    /**
+     * Creates a new toolbar. Notice: This toolbar does nothing
+     * until {@link #setMapPane(JEditorPane)} is called!
+     */
+    public JEditorToolBar() {
+      this(null);
+    }
+    
+    /**
+	 * Creates a new tool bar.
+	 * @param editorPane {@link JEditorPane} the tool bar controls
+	 */
+	public JEditorToolBar(JEditorPane editorPane) {
+	  super("Control the editor actions", JToolBar.HORIZONTAL);
+      this.actionButtons   = new TreeMap<Integer,JButton>();
+      // Create a Listener to sniff the zooms on the JMapPane
+      this.mapPaneListener = new JMapPaneListener() {
+          public void performMapPaneEvent(JMapPaneEvent e) {
+              if ( !(e instanceof JEditorPaneEvent) )
+                return;
+
+              // At the moment the layer editing is finished, the editor mode
+              // is not yet initialized. However for the button activation the
+              // mode NULL is essential in this case.
+              EditorMode mode = ((JEditorPaneEvent)e).getEditorMode();
+              if ( e instanceof LayerEditCanceledEvent ||
+                   e instanceof LayerEditFinishedEvent )
+                mode = null;
+              updateButtonActivation(mode);
+          }
+      };    
+     
+      setMapPane(editorPane);
+	  setFloatable(false);
+	  setRollover(true);
+	  
+	  init();
+	}
+	
+	/**
+	 * Sets the {@link JEditorPane} controlled by this tool bar.
+	 * @param editorPane {@link JEditorPane} to control (if {@code null} this
+	 *                   tool bar controls NOTHING!)
+	 */
+	public void setMapPane(JEditorPane editorPane) {
+	  // Remove listener from old MapPane
+	  if ( this.editorPane != null )
+	    this.editorPane.removeMapPaneListener( mapPaneListener );
+      this.editorPane = editorPane;
+      if ( this.editorPane != null && mapPaneListener != null )
+        this.editorPane.addMapPaneListener( mapPaneListener );
+	}
+	
+	/**
+	 * Calls {@link #initActions()} and then puts all action buttons
+	 * to the tool bar.
+	 */
+	protected void init() {
+	  initActions();
+	  initToolBar();
+	  updateButtonActivation(null);
+	}
+
+    /**
+     * Creates the action buttons and adds them to {@link #actionButtons}.
+     */
+    protected void initActions() {
+      // Action button to create a new layer
+      addAction( new EditorPaneToolBarAction(
+          LAYER_NEW,
+          this,
+          "button.layer.new",
+          new ImageIcon(JEditorPane.class.getResource("resource/icons/layer_new.png"))
+      ), false);
+
+      // Action button to finish a layer
+      addAction( new EditorPaneToolBarAction(
+          LAYER_SAVE,
+          this,
+          "button.layer.save",
+          new ImageIcon(JEditorPane.class.getResource("resource/icons/layer_finish.png"))
+      ), false);
+
+      // Action button to cancel a layer
+      addAction( new EditorPaneToolBarAction(
+          LAYER_CANCEL,
+          this,
+          "button.layer.cancel",
+          new ImageIcon(JEditorPane.class.getResource("resource/icons/layer_cancel.png"))
+      ), false);
+
+      // Action button to undo all editing action
+      addAction( new EditorPaneToolBarAction(
+          EDIT_CLEAR,
+          this,
+          "button.edit.clear",
+          new ImageIcon(JEditorPane.class.getResource("resource/icons/edit_clear.png"))
+      ), false);
+
+      // Action button to undo a editing action
+      addAction( new EditorPaneToolBarAction(
+          EDIT_UNDO,
+          this,
+          "button.edit.undo",
+          new ImageIcon(JEditorPane.class.getResource("resource/icons/edit_undo.png"))
+      ), false);
+
+      // Action button to redo a undone editing action
+      addAction( new EditorPaneToolBarAction(
+          EDIT_REDO,
+          this,
+          "button.edit.redo",
+          new ImageIcon(JEditorPane.class.getResource("resource/icons/edit_redo.png"))
+      ), false);
+
+      // Action button to finish a feature
+      addAction( new EditorPaneToolBarAction(
+          EDIT_FINISH,
+          this,
+          "button.edit.finish",
+          new ImageIcon(JEditorPane.class.getResource("resource/icons/edit_finish.png"))
+      ), false);
+    }
+    
+    /**
+     * Clears the GUI of all components and adds all action buttons to the
+     * tool bar.
+     */
+    protected void initToolBar() {
+      setAlignmentY( 1f );
+      removeAll();
+//      // Separator to the left of the tool actions to start
+//      // the tool buttons with the map (not with the coordinate grid)
+//      Dimension dimension = new Dimension( 49,10);
+//      addSeparator(dimension);
+//      // Space between tool buttons and action buttons
+//      Dimension dimension2 = new Dimension( 10,10);
+//      this.addSeparator(dimension2);
+      // Action buttons
+      for (JButton b : actionButtons.values())
+        add(b);
+    }
+    
+
+    /**
+     * Performs the action of an action button.
+     * @param tool the action
+     * @param e    the event of the button
+     */
+	protected void performActionButton(int action, ActionEvent e) {
+      if ( editorPane == null )
+        return;
+      
+      try {
+        // Perform the action "New layer"
+        if ( action == LAYER_NEW )
+          createNewLayer();
+        // Perform the action "Finish layer"
+        if ( action == LAYER_SAVE )
+          editorPane.finishEditing();
+        // Perform the action "Cancel layer"
+        if ( action == LAYER_CANCEL )
+          editorPane.cancelEditing();
+  
+        // Perform the action "Finish feature"
+        if ( action == EDIT_FINISH )
+          editorPane.finishFeature();
+        // Perform the action "Undo editing"
+        if ( action == EDIT_UNDO )
+          editorPane.undoEditing();
+        // Perform the action "Redo editing"
+        if ( action == EDIT_REDO )
+          editorPane.redoEditing();
+        // Perform the action "Clear editing"
+        if ( action == EDIT_CLEAR )
+          editorPane.undoAll();
+      } catch (Exception err) {
+        ExceptionDialog.show(err);
+      }
+	}
+	
+	/**
+	 * Sets the enables/disables property for every toolbar button according 
+	 * to the current editor state. 
+	 * @param editorMode editor mode (because some events are fired BEFORE
+	 *                   the new mode is set)
+	 */
+	protected void updateButtonActivation(EditorMode editorMode) {
+	  if ( editorPane == null ) {
+	    setAllActionsEnabled(false, false);
+	    return;
+	  }
+      getButton( LAYER_NEW ).setEnabled( editorMode == null );
+	  getButton( LAYER_SAVE ).setEnabled( editorMode != null );
+      getButton( LAYER_CANCEL ).setEnabled( editorMode != null );
+      getButton( EDIT_UNDO ).setEnabled( editorPane.isUndoPossible() );
+      getButton( EDIT_REDO ).setEnabled( editorPane.isRedoPossible() );
+      getButton( EDIT_CLEAR ).setEnabled( editorPane.isUndoPossible() );
+      getButton( EDIT_FINISH ).setEnabled( editorMode != null && editorMode != EditorMode.New_Point );
+	}
+	
+	/**
+	 * Starts new layer.
+	 */
+	protected void createNewLayer() {
+	  // Ask layer type and name
+	  ManualInputOption.Text titleOption = new ManualInputOption.Text(
+	      getResourceString("NewLayer.layer.title"), true, getResourceString("NewLayer.layer.title.default")
+      );
+	  SelectionInputOption.Radio<JEditorPane.EditorMode> typeOption = new SelectionInputOption.Radio<JEditorPane.EditorMode>(
+          getResourceString("NewLayer.layer.type"),
+          true,
+          new JEditorPane.EditorMode[] { EditorMode.New_Point, EditorMode.New_Line, EditorMode.New_Polygon },
+          new String[] { getResourceString("NewLayer.layer.type.point"), getResourceString("NewLayer.layer.type.line"), getResourceString("NewLayer.layer.type.polygon") }
+	  );
+	  FeatureTypeInputOption ftOption = new FeatureTypeInputOption(
+	      getResourceString("NewLayer.ftype.title"),
+	      false
+	  ) {
+	        // Checks whether "the_geom" is used as attribute name
+	        // --> not allowed because JEditorPane uses this attribute
+	        //     for the default geometry of new layers
+    	    public boolean performIsInputValid() {
+    	      if ( super.performIsInputValid() ) {
+    	        FeatureType ft = inpTableModel.createFeatureType();
+    	        if ( ft.getAttributeType( JEditorPane.GEOMETRY_ATTR ) != null )
+    	          throw new UnsupportedOperationException(getResourceString("NewLayer.Err.GeomAttr",JEditorPane.GEOMETRY_ATTR));
+    	      }
+    	      return true;
+    	    }
+	  };
+	  Object[] value = MultipleOptionPane.showMultipleInputDialog(
+	      this,
+	      getResourceString("NewLayer.dialog.title"),
+	      titleOption,
+	      typeOption,
+	      ftOption
+	  );
+	  if ( value == null )
+	    return; // Dialog canceled
+	  editorPane.setAdditionalAttributes( ftOption.getValue() );
+	  editorPane.startEditing(
+	      (JEditorPane.EditorMode)value[1],
+	      (String)value[0]
+	  );
+	}
+
+    /**
+     * Adds an action to the tool bar. Does nothing if a tool or action with the
+     * specified ID already exists!
+     * @param buttonAction action for the button
+     * @param resetToolBar indicates whether the toolbar GUI is reset after adding
+     *                     the button (if adding several actions it useful only to
+     *                     reset the GUI for the last added tool) 
+     */
+    public void addAction(EditorPaneToolBarAction buttonAction, boolean resetToolBar) {
+      if ( isButtonIDUsed(buttonAction.getID()) ) {
+        LOGGER.warn("addAction(.) ignored because ID already used for tool or action: "+buttonAction.getID());
+        return;
+      }
+      JButton button = new JButton(buttonAction);
+      actionButtons.put( buttonAction.getID(), button );
+      if ( resetToolBar )
+        initToolBar();
+    }
+
+    /**
+     * Adds an action to the tool bar and resets the toolbar GUI.
+     * @param buttonAction action for the toggle button
+     */
+    public void addAction(EditorPaneToolBarAction buttonAction) {
+      addAction(buttonAction, true);
+    }
+    
+    /**
+     * Returns the button for a specific tool or action.
+     * @param id the constant for a tool
+     * @return a {@link JButton} if {@code id} specifies an {@linkplain #getActionButton(int) action button}
+     *         or {@link JToogleButton} if {@code id} specifies a {@linkplain #getToolButton(int) tool button}
+     */
+    public AbstractButton getButton(int id) {
+      AbstractButton button = actionButtons.get(id);
+      if ( button == null )
+        LOGGER.warn("Unknown action ID: "+id);
+      return button;
+    }
+
+    /**
+     * Returns the button for a specific action.
+     * @param action the constant an action 
+     */
+    public JButton getActionButton(int action) {
+      AbstractButton button = getButton(action);
+      if ( button != null && !(button instanceof JButton) ) {
+        LOGGER.warn("ID specifies no action: "+action);
+        button = null;
+      }
+      return (JButton)button; 
+
+    }
+
+    /**
+     * Sets whether an action is activated or not. The visible property
+     * of the button is not affected.
+     * @param id actionID
+     * @param enabled if {@code true} the action becomes available
+     */
+    public void setButtonEnabled(int id, boolean enabled) {
+      AbstractButton button = getButton(id);
+      if ( button == null )
+        return;
+      button.setEnabled( enabled );
+    }
+
+    /**
+     * Sets whether an action is activated or not.
+     * @param id actionID
+     * @param enabled if {@code true} the tool becomes available
+     * @param hideOnDisable if {@code true} the button is also hidden if
+     *                      {@code enabled} is {@code false}
+     */
+	public void setButtonEnabled(int id, boolean enabled, boolean hideOnDisable) {
+	  AbstractButton button = getButton(id);
+	  if ( button == null )
+	    return;
+	  button.setEnabled( enabled );
+	  // if button is enabled, it becomes visible anyway
+	  // if button is disabled and the "hide" option is set, it is also hidden 
+	  if ( enabled )
+	    button.setVisible( true );
+	  else
+	    button.setVisible( !hideOnDisable );
+	}
+
+    /**
+     * Checks whether a ID is already used for a tool or action.
+     * @param tool tool ID
+     */
+    public boolean isButtonIDUsed(int id) {
+      return actionButtons.get(id) != null;
+    }
+
+    /**
+     * Checks whether a tool is activated.
+     * @param tool tool ID
+     * @return {@code false} if an unknown ID is specified
+     */
+    public boolean isButtonEnabled(int id) {
+      AbstractButton button = getButton(id);
+      if ( button != null )
+        return button.isEnabled();
+      return false;
+    }
+
+    /**
+     * Sets the activation for all actions.
+     * @param enabled if {@code true} all actions becomes available
+     * @param hideOnDisable if {@code true} the buttons are also hidden if
+     *                      {@code enabled} is {@code false}
+     */
+    public void setAllActionsEnabled(boolean enabled, boolean hideOnDisable) {
+      for (int tool : actionButtons.keySet())
+        setButtonEnabled(tool,enabled,hideOnDisable);
+    }   
+    
+    /**
+     * Returns the maximum ID of actions. 
+     */
+    public int getMaxActionID() {
+      return actionButtons.lastKey();
+    }
+
+    /**
+     * Returns the minimum ID of actions. 
+     */
+    public int getMinActionID() {
+      return actionButtons.firstKey();
+    }
+    
+    protected static String getResourceString(String key, Object... params) {
+      return GeotoolsGUIUtil.RESOURCE.getString("schmitzm.geotools.gui.JEditorToolBar."+key,params);
+    }
+    
+    /**
+     * Extends the {@link AbstractAction} with maintaining an ID and
+     * the {@link JEditorToolBar} the action controls.
+     * Additionally this class automatically calls
+     * {@link JEditorToolBar#performActionButton(int, ActionEvent)}.
+     * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+     */
+    public static class EditorPaneToolBarAction extends AbstractAction {
+      /** The ID of the action */
+      protected int id = -1;
+      /** The tool bar, this action is made for. */
+      protected JEditorToolBar toolBar = null;
+
+      /**
+       * Creates a new action with a dummy description and no icon.
+       * @param id      unique ID for the action
+       * @param toolBar toolbar this action is made for
+       */
+      public EditorPaneToolBarAction(int id, JEditorToolBar toolBar) {
+        this(id,toolBar,""+id);
+      }
+
+      /**
+       * Creates a new action without an icon.
+       * @param id      unique ID for the action
+       * @param toolBar toolbar this action is made for
+       * @param name    description used for buttons or menus 
+       */
+      public EditorPaneToolBarAction(int id, JEditorToolBar toolBar, String name) {
+        this(id,toolBar,name,null);
+      }
+
+      /**
+       * Creates a new action.
+       * @param id      unique ID for the action
+       * @param toolBar toolbar this action is made for
+       * @param name    description used for buttons or menus 
+       * @param icon    icon used for buttons or menus 
+       */
+      public EditorPaneToolBarAction(int id, JEditorToolBar toolBar, String name, Icon icon) {
+        super("",icon);
+        this.id      = id;
+        this.toolBar = toolBar;
+        this.putValue(SHORT_DESCRIPTION, getResourceString(name));
+      }
+
+      /**
+       * Calls {@link JEditorToolBar#performActionButton(int, ActionEvent)}.
+       */
+      public void actionPerformed(ActionEvent e) {
+        if ( toolBar.actionButtons.get(id) != null )
+          toolBar.performActionButton(id, e);
+      }
+      
+      /**
+       * Returns the (unique) id of this action.
+       * @return
+       */
+      public int getID() {
+        return id;
+      }
+    }
+}

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

Modified: trunk/src/schmitzm/geotools/gui/LayeredEditorFrame.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/LayeredEditorFrame.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/LayeredEditorFrame.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,93 +1,111 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.gui;
-
-import java.awt.BorderLayout;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-
-import schmitzm.geotools.feature.FeatureUtil.GeometryForm;
-import schmitzm.swing.JPanel;
-
-
-/**
- * Diese Klasse stellt ein Fenster dar, in dem layer-basiert Geo-Objekte
- * grafisch dargestellt <b>und neue Vektor-Layer erstellt</b> werden koennen.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class LayeredEditorFrame extends LayeredMapFrame {
-  /** Toolbar, der die Editier-Funktionen steuert. */
-  protected JEditorToolBar toolBar = null;
-  /** Toolbar, der die Style-Funktionen steuert. */
-  protected StyleToolBar styleBar = null;
-
-  /**
-   * Erzeugt ein neues (leeres) Editor-Fenster.
-   */
-  public LayeredEditorFrame() {
-    this(null,"");
-  }
-
-  /**
-   * Erzeugt ein neues (leeres) Editor-Fenster.
-   * @param lmp {@link LayeredMapPane} welches zur Anzeige der Karten verwendet wird (wenn
-   *            {@code null} wird eine neue {@link LayeredMapPane}-Instanz erzeugt)
-   */
-  public LayeredEditorFrame(LayeredMapPane lmp) {
-    this(lmp,"");
-  }
-
-  /**
-   * Erzeugt ein neues (leeres) Editor-Fenster.
-   * @param title Titel des Fensters
-   */
-  public LayeredEditorFrame(String title) {
-    this(null,title);
-  }
-
-  /**
-   * Erzeugt ein neues (leeres) Editor-Fenster.
-   * @param title Titel des Fensters
-   * @param lmp {@link LayeredMapPane} welches zur Anzeige der Karten verwendet wird (wenn
-   *            {@code null} wird eine neue {@link LayeredMapPane}-Instanz erzeugt)
-   */
-  public LayeredEditorFrame(LayeredMapPane lmp, String title) {
-    super( lmp != null ? lmp : new LayeredMapPane(new GeoMapPane(new JEditorPane(),null,null,null, null)),title);
-    if ( !(layeredMapPane.geoMapPane.mapPane instanceof JEditorPane) )
-      throw new IllegalArgumentException("LayeredMapPane must contain a JEditorPane to use in LayeredEditorFrame.");
-    this.toolBar  = new JEditorToolBar( (JEditorPane)layeredMapPane.geoMapPane.mapPane );
-    this.styleBar = new StyleToolBar();
-    // Add a listener to the style bar, to apply every style
-    // change to the map
-    this.styleBar.addPropertyChangeListener( new PropertyChangeListener() {
-      public void propertyChange(PropertyChangeEvent e) {
-        JEditorPane editorPane = (JEditorPane)layeredMapPane.geoMapPane.mapPane;
-        if ( e.getSource() == styleBar ) {
-          editorPane.setEditorStyle( GeometryForm.POINT,   styleBar.createPointStyle() );
-          editorPane.setEditorStyle( GeometryForm.LINE,    styleBar.createLineStyle() );
-          editorPane.setEditorStyle( GeometryForm.POLYGON, styleBar.createPolygonStyle() );
-          editorPane.refresh();
-        }
-
-      }
-    });
-
-    JPanel contentPane = new JPanel(new BorderLayout(0,5));
-    JPanel toolPane    = new JPanel(new BorderLayout() );
-    toolPane.add(toolBar, BorderLayout.NORTH);
-    toolPane.add(styleBar, BorderLayout.SOUTH);
-    contentPane.add( getContentPane(), BorderLayout.CENTER );
-    contentPane.add( toolPane, BorderLayout.NORTH );
-    setContentPane( contentPane );
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.gui;
+
+import java.awt.BorderLayout;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import schmitzm.geotools.feature.FeatureUtil.GeometryForm;
+import schmitzm.swing.JPanel;
+
+
+/**
+ * Diese Klasse stellt ein Fenster dar, in dem layer-basiert Geo-Objekte
+ * grafisch dargestellt <b>und neue Vektor-Layer erstellt</b> werden koennen.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class LayeredEditorFrame extends LayeredMapFrame {
+  /** Toolbar, der die Editier-Funktionen steuert. */
+  protected JEditorToolBar toolBar = null;
+  /** Toolbar, der die Style-Funktionen steuert. */
+  protected StyleToolBar styleBar = null;
+
+  /**
+   * Erzeugt ein neues (leeres) Editor-Fenster.
+   */
+  public LayeredEditorFrame() {
+    this(null,"");
+  }
+
+  /**
+   * Erzeugt ein neues (leeres) Editor-Fenster.
+   * @param lmp {@link LayeredMapPane} welches zur Anzeige der Karten verwendet wird (wenn
+   *            {@code null} wird eine neue {@link LayeredMapPane}-Instanz erzeugt)
+   */
+  public LayeredEditorFrame(LayeredMapPane lmp) {
+    this(lmp,"");
+  }
+
+  /**
+   * Erzeugt ein neues (leeres) Editor-Fenster.
+   * @param title Titel des Fensters
+   */
+  public LayeredEditorFrame(String title) {
+    this(null,title);
+  }
+
+  /**
+   * Erzeugt ein neues (leeres) Editor-Fenster.
+   * @param title Titel des Fensters
+   * @param lmp {@link LayeredMapPane} welches zur Anzeige der Karten verwendet wird (wenn
+   *            {@code null} wird eine neue {@link LayeredMapPane}-Instanz erzeugt)
+   */
+  public LayeredEditorFrame(LayeredMapPane lmp, String title) {
+    super( lmp != null ? lmp : new LayeredMapPane(new GeoMapPane(new JEditorPane(),null,null,null, null)),title);
+    if ( !(layeredMapPane.geoMapPane.mapPane instanceof JEditorPane) )
+      throw new IllegalArgumentException("LayeredMapPane must contain a JEditorPane to use in LayeredEditorFrame.");
+    this.toolBar  = new JEditorToolBar( (JEditorPane)layeredMapPane.geoMapPane.mapPane );
+    this.styleBar = new StyleToolBar();
+    // Add a listener to the style bar, to apply every style
+    // change to the map
+    this.styleBar.addPropertyChangeListener( new PropertyChangeListener() {
+      public void propertyChange(PropertyChangeEvent e) {
+        JEditorPane editorPane = (JEditorPane)layeredMapPane.geoMapPane.mapPane;
+        if ( e.getSource() == styleBar ) {
+          editorPane.setEditorStyle( GeometryForm.POINT,   styleBar.createPointStyle() );
+          editorPane.setEditorStyle( GeometryForm.LINE,    styleBar.createLineStyle() );
+          editorPane.setEditorStyle( GeometryForm.POLYGON, styleBar.createPolygonStyle() );
+          editorPane.refresh();
+        }
+
+      }
+    });
+
+    JPanel contentPane = new JPanel(new BorderLayout(0,5));
+    JPanel toolPane    = new JPanel(new BorderLayout() );
+    toolPane.add(toolBar, BorderLayout.NORTH);
+    toolPane.add(styleBar, BorderLayout.SOUTH);
+    contentPane.add( getContentPane(), BorderLayout.CENTER );
+    contentPane.add( toolPane, BorderLayout.NORTH );
+    setContentPane( contentPane );
+  }
+}

Modified: trunk/src/schmitzm/geotools/gui/LayeredMapFrame.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/LayeredMapFrame.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/LayeredMapFrame.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,236 +1,254 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.gui;
-
-import java.awt.BorderLayout;
-import java.awt.Dimension;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.util.Vector;
-
-import javax.swing.BorderFactory;
-import javax.swing.JFrame;
-import javax.swing.JPanel;
-
-import org.geotools.feature.FeatureCollection;
-import org.geotools.map.MapContext;
-import org.geotools.map.MapLayer;
-import org.geotools.map.event.MapLayerListEvent;
-import org.geotools.map.event.MapLayerListListener;
-
-import schmitzm.geotools.map.event.FeatureSelectedEvent;
-import schmitzm.geotools.map.event.GridCoverageSelectedEvent;
-import schmitzm.geotools.map.event.JMapPaneEvent;
-import schmitzm.geotools.map.event.JMapPaneListener;
-import schmitzm.swing.SelectionInputOption;
-import schmitzm.swing.SwingUtil;
-
-/**
- * Diese Klasse stellt ein Fenster dar, in dem layer-basiert Objekte
- * grafisch dargestellt werden koennen. Hinzugefuegt werden die Objekte
- * direkt in das {@link LayeredMapPane#addLayer(Object,String)}<br>
- * Welche Objekte dargestellt werden koennen, ist der Beschreibung der
- * {@link LayeredMapPane#isVisualisable(Object)}-Methode zu entnehmen.<br>
- * Das Fenster besteht aus 3 Komponenten:
- * <ol>
- * <li>Eine Map ({@link JMapPane}) zu grafischen Darstellung der Layer</li>
- * <li>Eine Liste mit Steuerungskomponenten, ueber die die einzelnen Layer
- *     angesprochen werden koennen (ein/ausblenden, zoomen, ...).</li>
- * <li>Eine Status-Zeile, in der die Koordinaten der aktuellen Mausposition
- *     angezeigt werden, sowie der Raster-Wert des obersten Rasters unterhalb
- *     des Mauszeigers.</li>
- * </ol>
- * Die grafischen Layer (in der Map) koennen wahlweise (de)aktiviert werden. Dies
- * geschieht durch setzen/entfernen eines Haekchens in der entsprechenden
- * Steuerungskomponente. Diese enthaelt zudem ein Kontextmenue, ueber welches
- * <ul>
- * <li>das jeweilige Layer aus der Map entfernt werden kann</li>
- * <li>das jeweilige Layer in der Map eine Ebene nach oben/unten verschoben werden kann</li>
- * <li>die Map sogezoomt werden kann, dass das jeweilige Layer komplett angezeigt wird</li>
- * </ul>
- * Um Layer einzufuegen koennen die {@code addLayer(.)}-Methoden des
- * {@link #getLayeredMapPane() LayeredMapPane} (dabei wird ein Default-Style verwendet)
- * oder die entsprechenden Methoden des {@link MapContext} ({@code getLayeredMapPane().getMapPane().getContext()}).
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class LayeredMapFrame extends JFrame {
-  private   JPanel                     contentPane      = null;
-  /** Karten- und Layer-Kontroll-Bereich. */
-  protected LayeredMapPane             layeredMapPane   = null;
-  private   JMapPane                   mapPane          = null;
-  private   MapContext                 mapContext       = null;
-  /** Status-Balken. */
-  protected MapPaneStatusBar           statusBar        = null;
-  /** Fenster fuer Feature-Details */
-  protected FeatureCollectionFrame     featuresFrame    = null;
-  /** Auswahlfeld fuer das Raster, fuer welches die Koordinaten angezeigt werden. */
-  protected SelectionInputOption<MapLayer> rasterComboBox   = null;
-
-  /**
-   * Erzeugt ein neues (leeres) Map-Fenster.
-   */
-  public LayeredMapFrame() {
-    this(null,"");
-  }
-
-  /**
-   * Erzeugt ein neues (leeres) Map-Fenster.
-   * @param lmp {@link LayeredMapPane} welches zur Anzeige der Karten verwendet wird (wenn
-   *            {@code null} wird eine neue {@link LayeredMapPane}-Instanz erzeugt)
-   */
-  public LayeredMapFrame(LayeredMapPane lmp) {
-    this(lmp,"");
-  }
-
-  /**
-   * Erzeugt ein neues (leeres) Map-Fenster.
-   * @param title Titel des Fensters
-   */
-  public LayeredMapFrame(String title) {
-    this(null,title);
-  }
-
-  /**
-   * Erzeugt ein neues (leeres) Map-Fenster.
-   * @param title Titel des Fensters
-   * @param lmp {@link LayeredMapPane} welches zur Anzeige der Karten verwendet wird (wenn
-   *            {@code null} wird eine neue {@link LayeredMapPane}-Instanz erzeugt)
-   */
-  public LayeredMapFrame(LayeredMapPane lmp, String title) {
-    super();
-    this.setSize(new Dimension(500, 400));
-    this.setTitle(title);
-    contentPane = (JPanel) this.getContentPane();
-    contentPane.setLayout(new GridBagLayout());
-
-    // Karte und Layer-Kontrolle
-    layeredMapPane = lmp != null ? lmp : new LayeredMapPane();
-    mapPane        = layeredMapPane.getMapPane();
-    mapContext     = mapPane.getContext();
-    MapActionControlPane mapControl = new MapActionControlPane(mapPane,MapActionControlPane.VERTICAL);
-    mapControl.setFloatable(false);
-
-    // unter Layer-Liste eine ComboBox mit Raster-Auswahl einfuegen
-    this.rasterComboBox   = new SelectionInputOption.Combo<MapLayer>("",false);
-    this.mapContext.addMapLayerListListener( new MapLayerListListener() {
-      public void layerChanged(MapLayerListEvent e) {
-        updateRasterComboBox();
-      }
-      public void layerMoved(MapLayerListEvent e) { }
-      public void layerAdded(MapLayerListEvent e) {
-        updateRasterComboBox();
-      }
-      public void layerRemoved(MapLayerListEvent e) {
-        updateRasterComboBox();
-      }
-    } );
-    this.layeredMapPane.horSplitPane.getContainer(0).add(
-        rasterComboBox, BorderLayout.SOUTH);
-
-
-    // Spezielles RasterPositionLabel in dem die Koordinaten des in der
-    // ComboBox ausgewaehlten Rasters angezeigt werden
-    RasterPositionLabel rpLabel = new RasterPositionLabel(1) {
-      protected MapLayer determineRasterLayer(final JMapPane mapPane) {
-        return rasterComboBox.getValue();
-      }
-    };
-
-    // Status-Zeile mit Raster-Auswahlfeld
-    statusBar = new MapPaneStatusBar(mapPane, rpLabel, null);
-    statusBar.setBorder( BorderFactory.createCompoundBorder(
-      BorderFactory.createLoweredBevelBorder(),
-      BorderFactory.createEmptyBorder(2,5,2,5)
-    ) );
-
-    // Status-Zeile mit Raster-Auswahlfeld kombinieren
-    JPanel statusBarContainer = new JPanel();
-    statusBarContainer.setLayout( new BorderLayout() );
-    statusBarContainer.add(rasterComboBox, BorderLayout.WEST);
-    statusBarContainer.add(statusBar, BorderLayout.CENTER);
-
-    // Root-SplitPane in Fenster einfuegen
-    contentPane.add(layeredMapPane, new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0
-        ,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
-    contentPane.add(mapControl, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0
-        ,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(2, 0, 0, 0), 0, 0));
-    contentPane.add(statusBarContainer, new GridBagConstraints(0, 1, 2, 1, 1.0, 0.0
-        ,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(2, 0, 0, 0), 0, 0));
-
-    // Fenster fuer Feature-Details
-    featuresFrame = new FeatureCollectionFrame(null,true);
-    featuresFrame.setSize( new Dimension(400,200) );
-    // Ausgewaehlte Features werden im Detail-Frame angezeigt
-    mapPane.addMapPaneListener( new JMapPaneListener() {
-      public void performMapPaneEvent(JMapPaneEvent e) {
-        // Wenn Features ueber die Maus aus der Karte ausgewaehlt werden,
-        // oeffnet sich ein Detail-Fenster
-        if ( e instanceof FeatureSelectedEvent && e.getSourceObject() == mapPane ) {
-          FeatureSelectedEvent fse = (FeatureSelectedEvent)e;
-          FeatureCollection    fc  = fse.getSelectionResult();
-          featuresFrame.setFeatureCollection(fc);
-          featuresFrame.setTitle( fse.getSourceLayer().getTitle()+" ["+fse.getSelectionRange()+"]" );
-          if ( !featuresFrame.isVisible() ) {
-              SwingUtil.setRelativeFramePosition(featuresFrame,1,0);
-          }
-          featuresFrame.setVisible(true);
-        }
-
-        if ( e instanceof GridCoverageSelectedEvent ) {
-          // ...
-        }
-      }
-    });
-  }
-
-
-  protected void updateRasterComboBox() {
-    // Letzte Auswahl merken
-    MapLayer         lastSelection   = (MapLayer)rasterComboBox.getValue();
-    // Alle Raster-Layer und Titel ermitteln
-    Vector<MapLayer> rasterLayer     = new Vector<MapLayer>();
-    Vector<String>   rasterLayerDesc = new Vector<String>();
-    for (MapLayer layer : mapPane.getContext().getLayers())
-      if ( mapPane.isGridCoverageLayer(layer) ) {
-        rasterLayer.add(layer);
-        rasterLayerDesc.add( layer.getTitle() );
-      }
-    // Auswahl neu setzen
-    rasterComboBox.setSelectionObjects(
-      rasterLayer.toArray( new MapLayer[0] ),
-      rasterLayerDesc.toArray()
-    );
-    // Wenn nur ein Raster zur Verfuegung steht, dieses autom. auswaehlen
-    if ( rasterLayer.size() == 1 )
-      lastSelection = rasterLayer.firstElement();
-    // Letzte Auswahl setzen
-    rasterComboBox.setSelectedItem(lastSelection);
-  }
-
-
-  /**
-   * Liefert den Karten- und Kontroll-Bereich des Fensters.
-   */
-  public LayeredMapPane getLayeredMapPane() {
-    return this.layeredMapPane;
-  }
-
-  /**
-   * Liefert den Status-Bereich des Fensters.
-   */
-  public MapPaneStatusBar getStatusBar() {
-    return this.statusBar;
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.gui;
+
+import java.awt.BorderLayout;
+import java.awt.Dimension;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.util.Vector;
+
+import javax.swing.BorderFactory;
+import javax.swing.JFrame;
+import javax.swing.JPanel;
+
+import org.geotools.feature.FeatureCollection;
+import org.geotools.map.MapContext;
+import org.geotools.map.MapLayer;
+import org.geotools.map.event.MapLayerListEvent;
+import org.geotools.map.event.MapLayerListListener;
+
+import schmitzm.geotools.map.event.FeatureSelectedEvent;
+import schmitzm.geotools.map.event.GridCoverageSelectedEvent;
+import schmitzm.geotools.map.event.JMapPaneEvent;
+import schmitzm.geotools.map.event.JMapPaneListener;
+import schmitzm.swing.SelectionInputOption;
+import schmitzm.swing.SwingUtil;
+
+/**
+ * Diese Klasse stellt ein Fenster dar, in dem layer-basiert Objekte
+ * grafisch dargestellt werden koennen. Hinzugefuegt werden die Objekte
+ * direkt in das {@link LayeredMapPane#addLayer(Object,String)}<br>
+ * Welche Objekte dargestellt werden koennen, ist der Beschreibung der
+ * {@link LayeredMapPane#isVisualisable(Object)}-Methode zu entnehmen.<br>
+ * Das Fenster besteht aus 3 Komponenten:
+ * <ol>
+ * <li>Eine Map ({@link JMapPane}) zu grafischen Darstellung der Layer</li>
+ * <li>Eine Liste mit Steuerungskomponenten, ueber die die einzelnen Layer
+ *     angesprochen werden koennen (ein/ausblenden, zoomen, ...).</li>
+ * <li>Eine Status-Zeile, in der die Koordinaten der aktuellen Mausposition
+ *     angezeigt werden, sowie der Raster-Wert des obersten Rasters unterhalb
+ *     des Mauszeigers.</li>
+ * </ol>
+ * Die grafischen Layer (in der Map) koennen wahlweise (de)aktiviert werden. Dies
+ * geschieht durch setzen/entfernen eines Haekchens in der entsprechenden
+ * Steuerungskomponente. Diese enthaelt zudem ein Kontextmenue, ueber welches
+ * <ul>
+ * <li>das jeweilige Layer aus der Map entfernt werden kann</li>
+ * <li>das jeweilige Layer in der Map eine Ebene nach oben/unten verschoben werden kann</li>
+ * <li>die Map sogezoomt werden kann, dass das jeweilige Layer komplett angezeigt wird</li>
+ * </ul>
+ * Um Layer einzufuegen koennen die {@code addLayer(.)}-Methoden des
+ * {@link #getLayeredMapPane() LayeredMapPane} (dabei wird ein Default-Style verwendet)
+ * oder die entsprechenden Methoden des {@link MapContext} ({@code getLayeredMapPane().getMapPane().getContext()}).
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class LayeredMapFrame extends JFrame {
+  private   JPanel                     contentPane      = null;
+  /** Karten- und Layer-Kontroll-Bereich. */
+  protected LayeredMapPane             layeredMapPane   = null;
+  private   JMapPane                   mapPane          = null;
+  private   MapContext                 mapContext       = null;
+  /** Status-Balken. */
+  protected MapPaneStatusBar           statusBar        = null;
+  /** Fenster fuer Feature-Details */
+  protected FeatureCollectionFrame     featuresFrame    = null;
+  /** Auswahlfeld fuer das Raster, fuer welches die Koordinaten angezeigt werden. */
+  protected SelectionInputOption<MapLayer> rasterComboBox   = null;
+
+  /**
+   * Erzeugt ein neues (leeres) Map-Fenster.
+   */
+  public LayeredMapFrame() {
+    this(null,"");
+  }
+
+  /**
+   * Erzeugt ein neues (leeres) Map-Fenster.
+   * @param lmp {@link LayeredMapPane} welches zur Anzeige der Karten verwendet wird (wenn
+   *            {@code null} wird eine neue {@link LayeredMapPane}-Instanz erzeugt)
+   */
+  public LayeredMapFrame(LayeredMapPane lmp) {
+    this(lmp,"");
+  }
+
+  /**
+   * Erzeugt ein neues (leeres) Map-Fenster.
+   * @param title Titel des Fensters
+   */
+  public LayeredMapFrame(String title) {
+    this(null,title);
+  }
+
+  /**
+   * Erzeugt ein neues (leeres) Map-Fenster.
+   * @param title Titel des Fensters
+   * @param lmp {@link LayeredMapPane} welches zur Anzeige der Karten verwendet wird (wenn
+   *            {@code null} wird eine neue {@link LayeredMapPane}-Instanz erzeugt)
+   */
+  public LayeredMapFrame(LayeredMapPane lmp, String title) {
+    super();
+    this.setSize(new Dimension(500, 400));
+    this.setTitle(title);
+    contentPane = (JPanel) this.getContentPane();
+    contentPane.setLayout(new GridBagLayout());
+
+    // Karte und Layer-Kontrolle
+    layeredMapPane = lmp != null ? lmp : new LayeredMapPane();
+    mapPane        = layeredMapPane.getMapPane();
+    mapContext     = mapPane.getContext();
+    MapActionControlPane mapControl = new MapActionControlPane(mapPane,MapActionControlPane.VERTICAL);
+    mapControl.setFloatable(false);
+
+    // unter Layer-Liste eine ComboBox mit Raster-Auswahl einfuegen
+    this.rasterComboBox   = new SelectionInputOption.Combo<MapLayer>("",false);
+    this.mapContext.addMapLayerListListener( new MapLayerListListener() {
+      public void layerChanged(MapLayerListEvent e) {
+        updateRasterComboBox();
+      }
+      public void layerMoved(MapLayerListEvent e) { }
+      public void layerAdded(MapLayerListEvent e) {
+        updateRasterComboBox();
+      }
+      public void layerRemoved(MapLayerListEvent e) {
+        updateRasterComboBox();
+      }
+    } );
+    this.layeredMapPane.horSplitPane.getContainer(0).add(
+        rasterComboBox, BorderLayout.SOUTH);
+
+
+    // Spezielles RasterPositionLabel in dem die Koordinaten des in der
+    // ComboBox ausgewaehlten Rasters angezeigt werden
+    RasterPositionLabel rpLabel = new RasterPositionLabel(1) {
+      protected MapLayer determineRasterLayer(final JMapPane mapPane) {
+        return rasterComboBox.getValue();
+      }
+    };
+
+    // Status-Zeile mit Raster-Auswahlfeld
+    statusBar = new MapPaneStatusBar(mapPane, rpLabel, null);
+    statusBar.setBorder( BorderFactory.createCompoundBorder(
+      BorderFactory.createLoweredBevelBorder(),
+      BorderFactory.createEmptyBorder(2,5,2,5)
+    ) );
+
+    // Status-Zeile mit Raster-Auswahlfeld kombinieren
+    JPanel statusBarContainer = new JPanel();
+    statusBarContainer.setLayout( new BorderLayout() );
+    statusBarContainer.add(rasterComboBox, BorderLayout.WEST);
+    statusBarContainer.add(statusBar, BorderLayout.CENTER);
+
+    // Root-SplitPane in Fenster einfuegen
+    contentPane.add(layeredMapPane, new GridBagConstraints(0, 0, 1, 1, 1.0, 1.0
+        ,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
+    contentPane.add(mapControl, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0
+        ,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(2, 0, 0, 0), 0, 0));
+    contentPane.add(statusBarContainer, new GridBagConstraints(0, 1, 2, 1, 1.0, 0.0
+        ,GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(2, 0, 0, 0), 0, 0));
+
+    // Fenster fuer Feature-Details
+    featuresFrame = new FeatureCollectionFrame(null,true);
+    featuresFrame.setSize( new Dimension(400,200) );
+    // Ausgewaehlte Features werden im Detail-Frame angezeigt
+    mapPane.addMapPaneListener( new JMapPaneListener() {
+      public void performMapPaneEvent(JMapPaneEvent e) {
+        // Wenn Features ueber die Maus aus der Karte ausgewaehlt werden,
+        // oeffnet sich ein Detail-Fenster
+        if ( e instanceof FeatureSelectedEvent && e.getSourceObject() == mapPane ) {
+          FeatureSelectedEvent fse = (FeatureSelectedEvent)e;
+          FeatureCollection    fc  = fse.getSelectionResult();
+          featuresFrame.setFeatureCollection(fc);
+          featuresFrame.setTitle( fse.getSourceLayer().getTitle()+" ["+fse.getSelectionRange()+"]" );
+          if ( !featuresFrame.isVisible() ) {
+              SwingUtil.setRelativeFramePosition(featuresFrame,1,0);
+          }
+          featuresFrame.setVisible(true);
+        }
+
+        if ( e instanceof GridCoverageSelectedEvent ) {
+          // ...
+        }
+      }
+    });
+  }
+
+
+  protected void updateRasterComboBox() {
+    // Letzte Auswahl merken
+    MapLayer         lastSelection   = (MapLayer)rasterComboBox.getValue();
+    // Alle Raster-Layer und Titel ermitteln
+    Vector<MapLayer> rasterLayer     = new Vector<MapLayer>();
+    Vector<String>   rasterLayerDesc = new Vector<String>();
+    for (MapLayer layer : mapPane.getContext().getLayers())
+      if ( mapPane.isGridCoverageLayer(layer) ) {
+        rasterLayer.add(layer);
+        rasterLayerDesc.add( layer.getTitle() );
+      }
+    // Auswahl neu setzen
+    rasterComboBox.setSelectionObjects(
+      rasterLayer.toArray( new MapLayer[0] ),
+      rasterLayerDesc.toArray()
+    );
+    // Wenn nur ein Raster zur Verfuegung steht, dieses autom. auswaehlen
+    if ( rasterLayer.size() == 1 )
+      lastSelection = rasterLayer.firstElement();
+    // Letzte Auswahl setzen
+    rasterComboBox.setSelectedItem(lastSelection);
+  }
+
+
+  /**
+   * Liefert den Karten- und Kontroll-Bereich des Fensters.
+   */
+  public LayeredMapPane getLayeredMapPane() {
+    return this.layeredMapPane;
+  }
+
+  /**
+   * Liefert den Status-Bereich des Fensters.
+   */
+  public MapPaneStatusBar getStatusBar() {
+    return this.statusBar;
+  }
+
+}

Modified: trunk/src/schmitzm/geotools/gui/LayeredMapPane.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/LayeredMapPane.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/LayeredMapPane.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,337 +1,355 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.gui;
-
-import java.awt.BorderLayout;
-import java.util.Hashtable;
-
-import javax.swing.JScrollPane;
-import javax.swing.JSplitPane;
-
-import org.geotools.coverage.Category;
-import org.geotools.coverage.GridSampleDimension;
-import org.geotools.coverage.grid.GridCoverage2D;
-import org.geotools.coverage.grid.GridCoverageFactory;
-import org.geotools.feature.FeatureCollection;
-import org.geotools.map.MapContext;
-import org.geotools.map.MapLayer;
-import org.geotools.map.event.MapLayerListEvent;
-import org.geotools.map.event.MapLayerListListener;
-import org.geotools.styling.ColorMap;
-import org.geotools.styling.Style;
-import org.opengis.geometry.Envelope;
-
-import schmitzm.geotools.feature.FeatureUtil;
-import schmitzm.geotools.grid.GridUtil;
-import schmitzm.geotools.styling.ColorMapManager;
-import schmitzm.swing.JPanel;
-import schmitzm.swing.MultiSplitPane;
-
-/**
- * Diese Klasse stellt ein Panel dar, in dem layer-basiert Objekte
- * grafisch dargestellt werden koennen.<br>
- * Welche Objekte dargestellt werden koennen, ist der Beschreibung der
- * {@link #isVisualisable(Object)}-Methode zu entnehmen.<br>
- * Das Fenster besteht aus 2 durch einen Divider voneinander getrennten
- * Komponenten:
- * <ol>
- * <li>Eine Map ({@link JMapPane}) zu grafischen Darstellung der Layer</li>
- * <li>Eine Liste mit Steuerungskomponenten, ueber die die einzelnen Layer
- *     angesprochen werden koennen (ein/ausblenden, zoomen, ...).</li>
- * </ol>
- * Die grafischen Layer (in der Map) koennen wahlweise (de)aktiviert werden. Dies
- * geschieht durch setzen/entfernen eines Haekchens in der entsprechenden
- * Steuerungskomponente. Diese enthaelt zudem ein Kontextmenue, ueber welches
- * <ul>
- * <li>das jeweilige Layer aus der Map entfernt werden kann</li>
- * <li>das jeweilige Layer in der Map eine Ebene nach oben/unten verschoben werden kann</li>
- * <li>die Map sogezoomt werden kann, dass das jeweilige Layer komplett angezeigt wird</li>
- * </ul>
- * Darueberhinaus verwaltet das {@code LayerMapPane} eine Liste von
- * {@link ColorMapManager Farbpaletten} fuer Rasterdaten, die durch die
- * Layer-Kontrolle den Raster-Layern zugewiesen werden koennen.<br>
- * Um Layer einzufuegen koennen die {@code addLayer(.)}-Methoden dieser Klasse
- * verwendet werden (dabei wird ein Default-Style verwendet) oder die
- * entsprechenden Methoden des {@link MapContext} ({@code getMapPane().getContext()}).
- * @author Martin Schmitz
- * @version 1.0
- */
-public class LayeredMapPane extends JPanel {
-  protected MultiSplitPane             horSplitPane     = new MultiSplitPane(2,JSplitPane.HORIZONTAL_SPLIT);
-  /** Komponente, in der die Karten, der Massstab und das Koordinaten-Raster
-   *  dargestellt werden */
-  protected GeoMapPane geoMapPane = null;
-  private   MapContext mapContext = null;
-  private   JMapPane   mapPane = null;
-  private   Hashtable<MapLayer,Object> layerObjects = new Hashtable<MapLayer,Object>();
-  /** Komponente, in der die Layer-Kontrolle dargestellt ist. */
-  protected MapContextControlPane layerControlList = null;
-  /** Auswahl an Farb-Paletten fuer Raster-Daten */
-  protected ColorMapManager colorMaps = null;
-
-
-  /**
-   * Erzeugt eine neue Komponente.
-   */
-  public LayeredMapPane() {
-    this(null);
-  }
-
-  /**
-   * Erzeugt eine neue Komponente.
-   * @param geoMapPane Komponente, die zum Anzeigen der Karten verwendet wird
-   *                   (wenn {@code null} wird eine neue {@link GeoMapPane}-Instanz
-   *                   erzeugt)
-   */
-  public LayeredMapPane(GeoMapPane geoMapPane) {
-    super();
-    if ( geoMapPane == null )
-      geoMapPane = new GeoMapPane();
-    this.setLayout( new BorderLayout() );
-
-    // rechter Bereich: Map, Grids und Scale
-    this.geoMapPane = geoMapPane != null ? geoMapPane : new GeoMapPane();
-    this.mapPane    = geoMapPane.getMapPane();
-    this.mapContext = mapPane.getContext();
-    this.mapContext.addMapLayerListListener( new MapLayerListListener() {
-      public void layerAdded(MapLayerListEvent e) { }
-      public void layerChanged(MapLayerListEvent e) { }
-      public void layerMoved(MapLayerListEvent e) { }
-      public void layerRemoved(MapLayerListEvent e) {
-        layerObjects.remove( e.getLayer() );
-      }
-    } );
-
-    // linker Bereich: Layer-Liste mit Auswahl der Layer
-    this.colorMaps        = new ColorMapManager();
-    this.layerControlList = new MapContextControlPane( mapPane, colorMaps );
-
-    // horizontales SplitPane initialisieren
-    for (int i=0; i<horSplitPane.getContainerCount(); i++)
-      horSplitPane.getContainer(i).setLayout( new BorderLayout() );
-    horSplitPane.setResizeWeigth( new double[] {0.2,0.8} );
-    horSplitPane.setDividerSize(5);
-    horSplitPane.setInnerBorder(null);
-    horSplitPane.getContainer(0).add(new JScrollPane(layerControlList),BorderLayout.CENTER);
-    horSplitPane.getContainer(1).add(geoMapPane);
-
-    this.add( horSplitPane );
-  }
-
-  /**
-   * Liefert den Karten-Bereich der Komponente.
-   */
-  public JMapPane getMapPane() {
-    return mapPane;
-  }
-
-  /**
-   * Liefert das in einem Layer dargestellte Objekt.
-   * @param layer ein Layer
-   */
-  public Object getMapObject(MapLayer layer) {
-    return layerObjects.get(layer);
-  }
-
-  /**
-   * Liefert den Manager fuer die zur Verfuegung stehenden Farbpaletten.
-   */
-  public ColorMapManager getColorMapManager() {
-    return this.colorMaps;
-  }
-
-  /**
-   * Prueft, ob Instanzen einer bestimmten Klasse von {@link LayeredMapFrame}
-   * visualisiert werden koennen. Dies gilt fuer
-   * <ul>
-   *   <li>{@link GridCoverage2D org.geotools.coverage.grid.GridCoverage2D}</li>
-   *   <li>{@link FeatureCollection org.geotools.feature.FeatureCollection}</li>
-   * </ul>
-   */
-  public boolean isVisualisable(Class c) {
-    return GridCoverage2D.class.isAssignableFrom( c ) ||
-           FeatureCollection.class.isAssignableFrom( c );
-  }
-
-  /**
-   * Prueft, ob eine Objekt-Instanz von {@link LayeredMapFrame}
-   * visualisiert werden kann. Dies gilt fuer Instanzen von
-   * <ul>
-   *   <li>{@link GridCoverage2D org.geotools.coverage.grid.GridCoverage2D}</li>
-   *   <li>{@link FeatureCollection org.geotools.feature.FeatureCollection}</li>
-   * </ul>
-   */
-  public boolean isVisualisable(Object o) {
-    return o instanceof GridCoverage2D ||
-           o instanceof FeatureCollection;
-  }
-
-  /**
-   * Fuegt ein Raster-Layer (als oberstes Layer) ein.
-   * @param gc ein Grid-Coverage
-   * @param desc Beschreibung fuer das Raster
-   * @param style Darstellungs-Style fuer das Layer
-   */
-  public MapLayer addLayer(GridCoverage2D gc, String desc, Style style) {
-//    GridSampleDimension gsd = gc.getSampleDimensions()[0];
-//    for (int i = 0; i < gsd.getCategories().size(); i++) {
-//      Category cat = (Category) gsd.getCategories().get(i);
-//      System.out.print("'" + cat.getName() + "'\t" + cat.getRange().toString() +"\t"+cat.isQuantitative()+"\t");
-//      for (int j = 0; j < cat.getColors().length; j++)
-//        System.out.print(cat.getColors()[j].toString() + ",");
-//      System.out.println("\n           > " + cat.toString() + "  (" + cat.getClass().getName() + ")");
-//    }
-
-//    // Farbiges Grid erzeugen
-//    Category[] c = new Category[0];
-//    try {
-//      c = new Category[] {
-////          (Category) gsd.getCategories().get(0),
-////          (Category) gsd.getCategories().get(1)
-//          CoverageUtil.createGeophysicsCategory( new Category("", new Color[]{Color.WHITE, Color.BLACK}, new NumberRange(0.0,255.0),1,0), true ),
-//          CoverageUtil.createGeophysicsCategory( new Category("No data", Color.YELLOW, Float.NaN), false ),
-////          CoverageUtil.createGeophysicsCategory( new Category("No data", new Color(0, 0, 0), Float.NaN), true ),
-////          CoverageUtil.createGeophysicsCategory( new Category("0", Color.BLACK, 0.0f), true ),
-////          CoverageUtil.createGeophysicsCategory( new Category("1", Color.BLACK, 1.0f), true ),
-////          CoverageUtil.createGeophysicsCategory( new Category("2", Color.BLACK, 2.0f), true ),
-////          CoverageUtil.createGeophysicsCategory( new Category("3", Color.BLACK, 3.0f), true ),
-////          CoverageUtil.createGeophysicsCategory( new Category("4", Color.BLACK, 4.0f), true ),
-////          CoverageUtil.createGeophysicsCategory( new Category("5", Color.BLACK, 5.0f), true )
-//      };
-//    } catch ( Exception err ) {
-//      err.printStackTrace();
-//    }
-//    gc = recolorGrid(gc,0,c);
-//
-//    gsd = gc.getSampleDimensions()[0];
-//    for (int i = 0; i < gsd.getCategories().size(); i++) {
-//      Category cat = (Category) gsd.getCategories().get(i);
-//      System.out.print("'" + cat.getName() + "'\t" + cat.getRange().toString() +"\t"+cat.isQuantitative()+"\t");
-//      for (int j = 0; j < cat.getColors().length; j++)
-//        System.out.print(cat.getColors()[j].toString() + ",");
-//      System.out.println("\n           > " + cat.toString() + "  (" + cat.getClass().getName() + ")");
-//    }
-
-    // Falls kein Style angegeben ist, aus der Standard-Farbpalete erstellen
-    if ( style == null ) {
-      ColorMap colorMap  = colorMaps.getDefaultColorMap();
-      style = GridUtil.createStyle(colorMap,1.0);
-    }
-    // Layer erzeugen
-    mapContext.addLayer(gc, style);
-    MapLayer newLayer = mapContext.getLayer(mapContext.getLayerCount() - 1);
-    newLayer.setTitle(desc);
-
-    // neuer Anzeigebereich: Das komplette Raster
-    if (mapPane.getMapArea() == null) {
-      Envelope e = gc.getEnvelope();
-      com.vividsolutions.jts.geom.Envelope newArea = new com.vividsolutions.jts.
-          geom.Envelope(
-              e.getUpperCorner().getOrdinate(0), // X1
-              e.getLowerCorner().getOrdinate(0), // X2
-              e.getUpperCorner().getOrdinate(1), // Y1
-              e.getLowerCorner().getOrdinate(1) // Y2
-          );
-      mapPane.setMapArea(newArea);
-    }
-
-    // Anzeige aktualisieren
-    mapPane.setReset(true);
-    mapPane.repaint();
-
-    // Wenn Rendering geklappt hat, zum Layer gehoerendes Objekt merken
-    layerObjects.put(newLayer,gc);
-
-    return newLayer;
-  }
-
-  /**
-   * Fuegt ein FeatureCollection-Layer (als oberstes Layer) ein.
-   * @param fc eine Feature-Collection
-   * @param desc Beschreibung fuer die Feature-Collection
-   * @param style Darstellungs-Style fuer das Layer
-   */
-  public MapLayer addLayer(FeatureCollection fc, String desc, Style style) {
-    if ( style == null )
-      style = FeatureUtil.createDefaultStyle(fc);
-    // Layer erzeugen
-    mapContext.addLayer(fc, style);
-    MapLayer newLayer = mapContext.getLayer(mapContext.getLayerCount() - 1);
-    newLayer.setTitle(desc);
-
-    // neuer Anzeigebereich: Die komplette FeatureCollection
-    if (mapPane.getMapArea() == null)
-      mapPane.setMapArea(fc.getBounds());
-
-    // Anzeige aktualisieren
-    mapPane.setReset(true);
-    mapPane.repaint();
-
-    // Wenn Rendering geklappt hat, zum Layer gehoerendes Objekt merken
-    layerObjects.put(newLayer,fc);
-
-    return newLayer;
-  }
-
-  /**
-   * Fuegt ein Layer (als oberstes Layer) ein.
-   * @param obj ein (darstellbares) Objekt
-   * @param desc Beschreibung fuer das Objekt
-   * @param style Darstellungs-Style fuer das Layer
-   * @exception UnsupportedOperationException falls ein nicht-darstellbares
-   *            Objekt uebergeben wird
-   * @see #isVisualisable(Object)
-   * @see #isVisualisable(Class)
-   */
-  public MapLayer addLayer(Object obj, String desc, Style style) {
-    if ( obj instanceof GridCoverage2D )
-      return addLayer( (GridCoverage2D)obj, desc, style );
-    if ( obj instanceof FeatureCollection )
-      return addLayer( (FeatureCollection)obj, desc, style );
-    throw new UnsupportedOperationException("LayeredMapFrame can not visualise objects of class "+obj.getClass().getName());
-  }
-
-  /**
-   * Fuegt ein Layer (als oberstes Layer) ein. Es wird ein Standard-Style zur
-   * Darstellung verwendet.
-   * @param obj ein (darstellbares) Objekt
-   * @param desc Beschreibung fuer das Objekt
-   * @exception UnsupportedOperationException falls ein nicht-darstellbares
-   *            Objekt uebergeben wird
-   * @see #isVisualisable(Object)
-   * @see #isVisualisable(Class)
-   */
-  public MapLayer addLayer(Object obj, String desc) {
-    return addLayer(obj,desc,null);
-  }
-
-  /**
-   * Erzeugt ein neues {@link GridCoverage2D} mit einer neuen Farb-Zuordnung.
-   * @param grid Basis-Grid
-   * @param band Band, dessen Farbe veraendert werden soll
-   * @param cat  Rasterwert/Farb-Zuordnungen
-   */
-  private static GridCoverage2D recolorGrid(GridCoverage2D grid, int band, Category[] cat) {
-    GridSampleDimension[] gsd = grid.getSampleDimensions();
-    gsd[band] = new GridSampleDimension(cat,gsd[band].getUnits());
-
-    return new GridCoverageFactory().create(
-      grid.getName(),
-      grid.getRenderedImage(),
-      grid.getEnvelope(),
-      gsd,
-      new GridCoverage2D[] {grid},
-      null
-    );
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.gui;
+
+import java.awt.BorderLayout;
+import java.util.Hashtable;
+
+import javax.swing.JScrollPane;
+import javax.swing.JSplitPane;
+
+import org.geotools.coverage.Category;
+import org.geotools.coverage.GridSampleDimension;
+import org.geotools.coverage.grid.GridCoverage2D;
+import org.geotools.coverage.grid.GridCoverageFactory;
+import org.geotools.feature.FeatureCollection;
+import org.geotools.map.MapContext;
+import org.geotools.map.MapLayer;
+import org.geotools.map.event.MapLayerListEvent;
+import org.geotools.map.event.MapLayerListListener;
+import org.geotools.styling.ColorMap;
+import org.geotools.styling.Style;
+import org.opengis.geometry.Envelope;
+
+import schmitzm.geotools.feature.FeatureUtil;
+import schmitzm.geotools.grid.GridUtil;
+import schmitzm.geotools.styling.ColorMapManager;
+import schmitzm.swing.JPanel;
+import schmitzm.swing.MultiSplitPane;
+
+/**
+ * Diese Klasse stellt ein Panel dar, in dem layer-basiert Objekte
+ * grafisch dargestellt werden koennen.<br>
+ * Welche Objekte dargestellt werden koennen, ist der Beschreibung der
+ * {@link #isVisualisable(Object)}-Methode zu entnehmen.<br>
+ * Das Fenster besteht aus 2 durch einen Divider voneinander getrennten
+ * Komponenten:
+ * <ol>
+ * <li>Eine Map ({@link JMapPane}) zu grafischen Darstellung der Layer</li>
+ * <li>Eine Liste mit Steuerungskomponenten, ueber die die einzelnen Layer
+ *     angesprochen werden koennen (ein/ausblenden, zoomen, ...).</li>
+ * </ol>
+ * Die grafischen Layer (in der Map) koennen wahlweise (de)aktiviert werden. Dies
+ * geschieht durch setzen/entfernen eines Haekchens in der entsprechenden
+ * Steuerungskomponente. Diese enthaelt zudem ein Kontextmenue, ueber welches
+ * <ul>
+ * <li>das jeweilige Layer aus der Map entfernt werden kann</li>
+ * <li>das jeweilige Layer in der Map eine Ebene nach oben/unten verschoben werden kann</li>
+ * <li>die Map sogezoomt werden kann, dass das jeweilige Layer komplett angezeigt wird</li>
+ * </ul>
+ * Darueberhinaus verwaltet das {@code LayerMapPane} eine Liste von
+ * {@link ColorMapManager Farbpaletten} fuer Rasterdaten, die durch die
+ * Layer-Kontrolle den Raster-Layern zugewiesen werden koennen.<br>
+ * Um Layer einzufuegen koennen die {@code addLayer(.)}-Methoden dieser Klasse
+ * verwendet werden (dabei wird ein Default-Style verwendet) oder die
+ * entsprechenden Methoden des {@link MapContext} ({@code getMapPane().getContext()}).
+ * @author Martin Schmitz
+ * @version 1.0
+ */
+public class LayeredMapPane extends JPanel {
+  protected MultiSplitPane             horSplitPane     = new MultiSplitPane(2,JSplitPane.HORIZONTAL_SPLIT);
+  /** Komponente, in der die Karten, der Massstab und das Koordinaten-Raster
+   *  dargestellt werden */
+  protected GeoMapPane geoMapPane = null;
+  private   MapContext mapContext = null;
+  private   JMapPane   mapPane = null;
+  private   Hashtable<MapLayer,Object> layerObjects = new Hashtable<MapLayer,Object>();
+  /** Komponente, in der die Layer-Kontrolle dargestellt ist. */
+  protected MapContextControlPane layerControlList = null;
+  /** Auswahl an Farb-Paletten fuer Raster-Daten */
+  protected ColorMapManager colorMaps = null;
+
+
+  /**
+   * Erzeugt eine neue Komponente.
+   */
+  public LayeredMapPane() {
+    this(null);
+  }
+
+  /**
+   * Erzeugt eine neue Komponente.
+   * @param geoMapPane Komponente, die zum Anzeigen der Karten verwendet wird
+   *                   (wenn {@code null} wird eine neue {@link GeoMapPane}-Instanz
+   *                   erzeugt)
+   */
+  public LayeredMapPane(GeoMapPane geoMapPane) {
+    super();
+    if ( geoMapPane == null )
+      geoMapPane = new GeoMapPane();
+    this.setLayout( new BorderLayout() );
+
+    // rechter Bereich: Map, Grids und Scale
+    this.geoMapPane = geoMapPane != null ? geoMapPane : new GeoMapPane();
+    this.mapPane    = geoMapPane.getMapPane();
+    this.mapContext = mapPane.getContext();
+    this.mapContext.addMapLayerListListener( new MapLayerListListener() {
+      public void layerAdded(MapLayerListEvent e) { }
+      public void layerChanged(MapLayerListEvent e) { }
+      public void layerMoved(MapLayerListEvent e) { }
+      public void layerRemoved(MapLayerListEvent e) {
+        layerObjects.remove( e.getLayer() );
+      }
+    } );
+
+    // linker Bereich: Layer-Liste mit Auswahl der Layer
+    this.colorMaps        = new ColorMapManager();
+    this.layerControlList = new MapContextControlPane( mapPane, colorMaps );
+
+    // horizontales SplitPane initialisieren
+    for (int i=0; i<horSplitPane.getContainerCount(); i++)
+      horSplitPane.getContainer(i).setLayout( new BorderLayout() );
+    horSplitPane.setResizeWeigth( new double[] {0.2,0.8} );
+    horSplitPane.setDividerSize(5);
+    horSplitPane.setInnerBorder(null);
+    horSplitPane.getContainer(0).add(new JScrollPane(layerControlList),BorderLayout.CENTER);
+    horSplitPane.getContainer(1).add(geoMapPane);
+
+    this.add( horSplitPane );
+  }
+
+  /**
+   * Liefert den Karten-Bereich der Komponente.
+   */
+  public JMapPane getMapPane() {
+    return mapPane;
+  }
+
+  /**
+   * Liefert das in einem Layer dargestellte Objekt.
+   * @param layer ein Layer
+   */
+  public Object getMapObject(MapLayer layer) {
+    return layerObjects.get(layer);
+  }
+
+  /**
+   * Liefert den Manager fuer die zur Verfuegung stehenden Farbpaletten.
+   */
+  public ColorMapManager getColorMapManager() {
+    return this.colorMaps;
+  }
+
+  /**
+   * Prueft, ob Instanzen einer bestimmten Klasse von {@link LayeredMapFrame}
+   * visualisiert werden koennen. Dies gilt fuer
+   * <ul>
+   *   <li>{@link GridCoverage2D org.geotools.coverage.grid.GridCoverage2D}</li>
+   *   <li>{@link FeatureCollection org.geotools.feature.FeatureCollection}</li>
+   * </ul>
+   */
+  public boolean isVisualisable(Class c) {
+    return GridCoverage2D.class.isAssignableFrom( c ) ||
+           FeatureCollection.class.isAssignableFrom( c );
+  }
+
+  /**
+   * Prueft, ob eine Objekt-Instanz von {@link LayeredMapFrame}
+   * visualisiert werden kann. Dies gilt fuer Instanzen von
+   * <ul>
+   *   <li>{@link GridCoverage2D org.geotools.coverage.grid.GridCoverage2D}</li>
+   *   <li>{@link FeatureCollection org.geotools.feature.FeatureCollection}</li>
+   * </ul>
+   */
+  public boolean isVisualisable(Object o) {
+    return o instanceof GridCoverage2D ||
+           o instanceof FeatureCollection;
+  }
+
+  /**
+   * Fuegt ein Raster-Layer (als oberstes Layer) ein.
+   * @param gc ein Grid-Coverage
+   * @param desc Beschreibung fuer das Raster
+   * @param style Darstellungs-Style fuer das Layer
+   */
+  public MapLayer addLayer(GridCoverage2D gc, String desc, Style style) {
+//    GridSampleDimension gsd = gc.getSampleDimensions()[0];
+//    for (int i = 0; i < gsd.getCategories().size(); i++) {
+//      Category cat = (Category) gsd.getCategories().get(i);
+//      System.out.print("'" + cat.getName() + "'\t" + cat.getRange().toString() +"\t"+cat.isQuantitative()+"\t");
+//      for (int j = 0; j < cat.getColors().length; j++)
+//        System.out.print(cat.getColors()[j].toString() + ",");
+//      System.out.println("\n           > " + cat.toString() + "  (" + cat.getClass().getName() + ")");
+//    }
+
+//    // Farbiges Grid erzeugen
+//    Category[] c = new Category[0];
+//    try {
+//      c = new Category[] {
+////          (Category) gsd.getCategories().get(0),
+////          (Category) gsd.getCategories().get(1)
+//          CoverageUtil.createGeophysicsCategory( new Category("", new Color[]{Color.WHITE, Color.BLACK}, new NumberRange(0.0,255.0),1,0), true ),
+//          CoverageUtil.createGeophysicsCategory( new Category("No data", Color.YELLOW, Float.NaN), false ),
+////          CoverageUtil.createGeophysicsCategory( new Category("No data", new Color(0, 0, 0), Float.NaN), true ),
+////          CoverageUtil.createGeophysicsCategory( new Category("0", Color.BLACK, 0.0f), true ),
+////          CoverageUtil.createGeophysicsCategory( new Category("1", Color.BLACK, 1.0f), true ),
+////          CoverageUtil.createGeophysicsCategory( new Category("2", Color.BLACK, 2.0f), true ),
+////          CoverageUtil.createGeophysicsCategory( new Category("3", Color.BLACK, 3.0f), true ),
+////          CoverageUtil.createGeophysicsCategory( new Category("4", Color.BLACK, 4.0f), true ),
+////          CoverageUtil.createGeophysicsCategory( new Category("5", Color.BLACK, 5.0f), true )
+//      };
+//    } catch ( Exception err ) {
+//      err.printStackTrace();
+//    }
+//    gc = recolorGrid(gc,0,c);
+//
+//    gsd = gc.getSampleDimensions()[0];
+//    for (int i = 0; i < gsd.getCategories().size(); i++) {
+//      Category cat = (Category) gsd.getCategories().get(i);
+//      System.out.print("'" + cat.getName() + "'\t" + cat.getRange().toString() +"\t"+cat.isQuantitative()+"\t");
+//      for (int j = 0; j < cat.getColors().length; j++)
+//        System.out.print(cat.getColors()[j].toString() + ",");
+//      System.out.println("\n           > " + cat.toString() + "  (" + cat.getClass().getName() + ")");
+//    }
+
+    // Falls kein Style angegeben ist, aus der Standard-Farbpalete erstellen
+    if ( style == null ) {
+      ColorMap colorMap  = colorMaps.getDefaultColorMap();
+      style = GridUtil.createStyle(colorMap,1.0);
+    }
+    // Layer erzeugen
+    mapContext.addLayer(gc, style);
+    MapLayer newLayer = mapContext.getLayer(mapContext.getLayerCount() - 1);
+    newLayer.setTitle(desc);
+
+    // neuer Anzeigebereich: Das komplette Raster
+    if (mapPane.getMapArea() == null) {
+      Envelope e = gc.getEnvelope();
+      com.vividsolutions.jts.geom.Envelope newArea = new com.vividsolutions.jts.
+          geom.Envelope(
+              e.getUpperCorner().getOrdinate(0), // X1
+              e.getLowerCorner().getOrdinate(0), // X2
+              e.getUpperCorner().getOrdinate(1), // Y1
+              e.getLowerCorner().getOrdinate(1) // Y2
+          );
+      mapPane.setMapArea(newArea);
+    }
+
+    // Anzeige aktualisieren
+    mapPane.setReset(true);
+    mapPane.repaint();
+
+    // Wenn Rendering geklappt hat, zum Layer gehoerendes Objekt merken
+    layerObjects.put(newLayer,gc);
+
+    return newLayer;
+  }
+
+  /**
+   * Fuegt ein FeatureCollection-Layer (als oberstes Layer) ein.
+   * @param fc eine Feature-Collection
+   * @param desc Beschreibung fuer die Feature-Collection
+   * @param style Darstellungs-Style fuer das Layer
+   */
+  public MapLayer addLayer(FeatureCollection fc, String desc, Style style) {
+    if ( style == null )
+      style = FeatureUtil.createDefaultStyle(fc);
+    // Layer erzeugen
+    mapContext.addLayer(fc, style);
+    MapLayer newLayer = mapContext.getLayer(mapContext.getLayerCount() - 1);
+    newLayer.setTitle(desc);
+
+    // neuer Anzeigebereich: Die komplette FeatureCollection
+    if (mapPane.getMapArea() == null)
+      mapPane.setMapArea(fc.getBounds());
+
+    // Anzeige aktualisieren
+    mapPane.setReset(true);
+    mapPane.repaint();
+
+    // Wenn Rendering geklappt hat, zum Layer gehoerendes Objekt merken
+    layerObjects.put(newLayer,fc);
+
+    return newLayer;
+  }
+
+  /**
+   * Fuegt ein Layer (als oberstes Layer) ein.
+   * @param obj ein (darstellbares) Objekt
+   * @param desc Beschreibung fuer das Objekt
+   * @param style Darstellungs-Style fuer das Layer
+   * @exception UnsupportedOperationException falls ein nicht-darstellbares
+   *            Objekt uebergeben wird
+   * @see #isVisualisable(Object)
+   * @see #isVisualisable(Class)
+   */
+  public MapLayer addLayer(Object obj, String desc, Style style) {
+    if ( obj instanceof GridCoverage2D )
+      return addLayer( (GridCoverage2D)obj, desc, style );
+    if ( obj instanceof FeatureCollection )
+      return addLayer( (FeatureCollection)obj, desc, style );
+    throw new UnsupportedOperationException("LayeredMapFrame can not visualise objects of class "+obj.getClass().getName());
+  }
+
+  /**
+   * Fuegt ein Layer (als oberstes Layer) ein. Es wird ein Standard-Style zur
+   * Darstellung verwendet.
+   * @param obj ein (darstellbares) Objekt
+   * @param desc Beschreibung fuer das Objekt
+   * @exception UnsupportedOperationException falls ein nicht-darstellbares
+   *            Objekt uebergeben wird
+   * @see #isVisualisable(Object)
+   * @see #isVisualisable(Class)
+   */
+  public MapLayer addLayer(Object obj, String desc) {
+    return addLayer(obj,desc,null);
+  }
+
+  /**
+   * Erzeugt ein neues {@link GridCoverage2D} mit einer neuen Farb-Zuordnung.
+   * @param grid Basis-Grid
+   * @param band Band, dessen Farbe veraendert werden soll
+   * @param cat  Rasterwert/Farb-Zuordnungen
+   */
+  private static GridCoverage2D recolorGrid(GridCoverage2D grid, int band, Category[] cat) {
+    GridSampleDimension[] gsd = grid.getSampleDimensions();
+    gsd[band] = new GridSampleDimension(cat,gsd[band].getUnits());
+
+    return new GridCoverageFactory().create(
+      grid.getName(),
+      grid.getRenderedImage(),
+      grid.getEnvelope(),
+      gsd,
+      new GridCoverage2D[] {grid},
+      null
+    );
+  }
+
+}

Modified: trunk/src/schmitzm/geotools/gui/MapActionControlPane.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/MapActionControlPane.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/MapActionControlPane.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,393 +1,411 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.gui;
-
-import java.awt.Component;
-import java.awt.event.ActionEvent;
-import java.util.Map;
-
-import javax.swing.AbstractAction;
-import javax.swing.ButtonGroup;
-import javax.swing.Icon;
-import javax.swing.JButton;
-import javax.swing.JToggleButton;
-import javax.swing.JToolBar;
-
-import schmitzm.geotools.map.event.FeatureSelectedEvent;
-import schmitzm.swing.CaptionsChangeable;
-import schmitzm.swing.SwingUtil;
-
-/**
- * Diese Klasse stellt einen {@link JToolBar} dar, mit dem zwischen den
- * verschiedenen "Klick"- und "Drag"-Aktionen des {@link JMapPane} gewechselt werden
- * kann:
- * <ul>
- *   <li><b>Info:</b>
- *       <ul>
- *         <li>Links-Klick:  nichts</li>
- *         <li>Links-Drag: nichts</li>
- *         <li>Rechts-Klick: nichts</li>
- *         <li>Rechts-Drag: Karten-Ausschnitt verschieben</li>
- *       </ul></li>
- *   <li><b>Zoom:</b>
- *       <ul>
- *         <li>Links-Klick:  Zoom in</li>
- *         <li>Links-Drag: Zoom in auf selektierten Bereich</li>
- *         <li>Rechts-Klick: Zoom out</li>
- *         <li>Rechts-Drag: Karten-Ausschnitt verschieben</li>
- *       </ul></li>
- *   <li><b>SelectTop:</b><br>
- *       Die Auswahl-Aktionen beziehen sich auf das oberste sichtbare Feature
- *       und fuehren zu einem {@link FeatureSelectedEvent}:
- *       <ul>
- *         <li>Links-Klick: einzelnes Feature selektieren</li>
- *         <li>Links-Drag: alle Features im selektierten Bereich auswaehlen</li>
- *         <li>Rechts-Klick: nichts</li>
- *         <li>Rechts-Drag: Karten-Ausschnitt verschieben</li>
- *       </ul></li>
- *   <li><b>SelectAll:</b><br>
- *       Wie <i>SelectTop</i>. Die Auswahl-Aktionen beziehen sich jedoch auf
- *       auf alle prinzipiell sichtbaren Layer (evt. verdeckte Features unterer
- *       Layer werden auch ausgewaehlt!)
- *       </li>
- * </ul>
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class MapActionControlPane extends JToolBar implements CaptionsChangeable {
-  /** Konstante um die Aktion "Info" in der Mask der zur Verfuegung stehenden
-   *  Buttons anzusprechen. */
-  public static final int ACTION_INFO = 1;
-  /** Konstante um die Aktion "Zoom" in der Mask der zur Verfuegung stehenden
-   *  Buttons anzusprechen. */
-  public static final int ACTION_ZOOM_IN = 2;
-  /** Konstante um die Aktion "SelectAll" in der Mask der zur Verfuegung stehenden
-   *  Buttons anzusprechen. */
-  public static final int ACTION_SELECT_ALL = 4;
-  /** Konstante um die Aktion "SelectTop" in der Mask der zur Verfuegung stehenden
-   *  Buttons anzusprechen. */
-  public static final int ACTION_SELECT_TOP = 8;
-  /** Konstante um die ALLE Aktionen in der Mask der zur Verfuegung stehenden
-   *  Buttons anzusprechen. */
-  public static final int ACTION_ALL = 0xFFFFFFFF;
-
-  /** Key-Konstante um die Aktion "Info" anzusprechen.
-   *  @see #resetCaptions(Map) */
-  public static final String INFO = MapActionControlPane.class.getName()+".INFO";
-  /** Key-Konstante um die Aktion "Zoom" anzusprechen.
-   *  @see #resetCaptions(Map) */
-  public static final String ZOOM_IN = MapActionControlPane.class.getName()+".ZOOM_IN";
-  /** Key-Konstante um die Aktion "SelectAll" anzusprechen.
-   *  @see #resetCaptions(Map) */
-  public static final String SELECT_ALL = MapActionControlPane.class.getName()+".SELECT_ALL";
-  /** Key-Konstante um die Aktion "SelectTop" anzusprechen.
-   *  @see #resetCaptions(Map) */
-  public static final String SELECT_TOP = MapActionControlPane.class.getName()+".SELECT_TOP";
-
-
-  /** {@link JMapPane} das gesteuert wird. */
-  protected JMapPane mapPane = null;
-  /** Button fuer Info-Aktion. */
-  protected JToggleButton infoState = null;
-  /** Button fuer Zoom-Aktion. */
-  protected JToggleButton zoomState = null;
-  /** Button fuer SelectTop-Aktion. */
-  protected JToggleButton selectTopState = null;
-  /** Button fuer SelectAll-Aktion. */
-  protected JToggleButton selectAllState = null;
-  /** Maske, die die zur Verfuegung stehenden Aktionen codiert */
-  protected int actionMask = 0;
-
-  /**
-   * Erzeugt eine horizontale Steuer-Komponente, die (noch) keinem {@link JMapPane}
-   * zugeordnet ist.
-   */
-  public MapActionControlPane() {
-    this( null, HORIZONTAL );
-  }
-
-  /**
-   * Erzeugt eine horizontale Steuer-Komponente.
-   * @param mapPane {@link JMapPane} das gesteuert wird
-   */
-  public MapActionControlPane(JMapPane mapPane) {
-    this( mapPane, HORIZONTAL );
-  }
-
-  /**
-   * Erzeugt eine Steuer-Komponente.
-   * @param mapPane {@link JMapPane} das gesteuert wird
-   * @param orientation Orientierung der Komponente ({@link #HORIZONTAL}/{@link #VERTICAL})
-   * @param actionMask definiert, welche Aktionen (in Form von Buttons) angezeigt werden
-   *                   (OR-Verknuepfung der {@code ACTION}-Konstanten
-   */
-  public MapActionControlPane(JMapPane mapPane, int orientation, int actionMask) {
-    super(orientation);
-    this.actionMask = actionMask;
-    // Button erzeugen und in Gruppe einfuegen, damit immer nur
-    // eine aktiviert ist
-    infoState      = new JToggleButton( new Action_InfoState() );
-    zoomState      = new JToggleButton( new Action_ZoomState() );
-    selectTopState = new JToggleButton( new Action_SelectOnTopLayerState() );
-    selectAllState = new JToggleButton( new Action_SelectOnAllLayerState() );
-    ButtonGroup bGroup = new ButtonGroup();
-    bGroup.add(infoState);
-    bGroup.add(zoomState);
-    bGroup.add(selectTopState);
-    bGroup.add(selectAllState);
-    // Button dem ToolBar hinzufuegen
-    if ( isActionVisible(ACTION_INFO) )
-      this.add(infoState);
-    if ( isActionVisible(ACTION_ZOOM_IN) )
-      this.add(zoomState);
-    if ( isActionVisible(ACTION_SELECT_TOP) )
-      this.add(selectTopState);
-    if ( isActionVisible(ACTION_SELECT_ALL) )
-      this.add(selectAllState);
-
-    setMapPane(mapPane);
-  }
-
-  /**
-   * Erzeugt eine Steuer-Komponente. Alle Aktionen sind sichtbar.
-   * @param mapPane {@link JMapPane} das gesteuert wird
-   * @param orientation Orientierung der Komponente ({@link #HORIZONTAL}/{@link #VERTICAL})
-   */
-  public MapActionControlPane(JMapPane mapPane, int orientation) {
-    this(mapPane,orientation,ACTION_ALL);
-  }
-
-  /**
-   * Setzt die Aktivierung der Aktionen entsprechend den Einstellungen
-   * des {@code JMapPane}.
-   * @see JMapPane#getWindowSelectionState()
-   */
-  public void resetActions() {
-    for (int i=0; i<getComponentCount(); i++) {
-      Component comp = getComponent(i);
-      if ( comp instanceof JButton )
-        ((JButton)comp).setSelected(false);
-    }
-
-    // Buttons entsprechend dem MapPane-Status einstellen
-    infoState.doClick();
-    if ( mapPane != null ) {
-      switch( mapPane.getWindowSelectionState() ) {
-        case JMapPane.ZOOM_IN:     if ( isActionVisible(ACTION_ZOOM_IN) )
-                                     zoomState.doClick();
-                                   break;
-        case JMapPane.SELECT_TOP:  if ( isActionVisible(ACTION_SELECT_TOP) )
-                                     selectTopState.doClick();
-                                   break;
-        case JMapPane.SELECT_ALL:  if ( isActionVisible(ACTION_SELECT_ALL) )
-                                     selectAllState.doClick();
-                                   break;
-        case JMapPane.NONE:        if ( isActionVisible(ACTION_INFO) )
-                                     infoState.doClick();
-                                   break;
-      }
-    }
-  }
-
-  /**
-   * Prueft, ob eine Aktion (Button) zur Verfuegung steht.
-   * @param action Aktion codiert durch eine {@code ACTION}-Konstante
-   */
-  public boolean isActionVisible(int action) {
-    return (actionMask & action) > 0;
-  }
-
-  /**
-   * Setzt das {@link JMapPane}, das durch diese Komponente gesteuert wird.
-   */
-  public void setMapPane(JMapPane mapPane) {
-    this.mapPane = mapPane;
-    resetActions();
-  }
-
-  /**
-   * Liefert das {@link JMapPane}, das durch diese Komponente gesteuert wird.
-   */
-  public JMapPane getMapPane() {
-    return this.mapPane;
-  }
-
-  /**
-   * Belegt die Beschriftungen der Aktionen neu.
-   * @param newCaptions enhaelt die neuen Beschriftungen
-   * @see #INFO
-   * @see #ZOOM_IN
-   * @see #SELECT_TOP
-   * @see #SELECT_ALL
-   */
-  public void resetCaptions(Map<String,Object> newCaptions) {
-    if ( newCaptions == null )
-      return;
-    Object caption = newCaptions.get(INFO);
-    if ( caption != null )
-      infoState.getAction().putValue(AbstractAction.SHORT_DESCRIPTION,caption);
-    caption = newCaptions.get(ZOOM_IN);
-    if ( caption != null )
-      zoomState.getAction().putValue(AbstractAction.SHORT_DESCRIPTION,caption);
-    caption = newCaptions.get(SELECT_TOP);
-    if ( caption != null )
-      selectTopState.getAction().putValue(AbstractAction.SHORT_DESCRIPTION,caption);
-    caption = newCaptions.get(SELECT_ALL);
-    if ( caption != null )
-      selectAllState.getAction().putValue(AbstractAction.SHORT_DESCRIPTION,caption);
-  }
-
-  ///////////////////////////////////////////////////////////////////
-  /////////////////////   Button Aktionen   /////////////////////////
-  ///////////////////////////////////////////////////////////////////
-  /**
-   * Aktion "Info" des {@link MapActionControlPane}.
-   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-   * @version 1.0
-   */
-  protected class Action_InfoState extends AbstractAction {
-    /**
-     * Erzeugt einen neue Info-Aktion
-     */
-    public Action_InfoState() {
-      super();
-      Icon icon = SwingUtil.createImageIconFromResourcePath("resource/icons/small/info.gif","Info");
-      this.putValue( SHORT_DESCRIPTION, GeotoolsGUIUtil.RESOURCE.getString( INFO ) );
-      this.putValue( SMALL_ICON, icon );
-      if ( icon == null )
-        this.putValue( NAME, "Info" );
-    }
-
-    /**
-     * Fuehrt die Info-Aktion aus.
-     * <ol>
-     *   <li>{@code JMapPane.setWindowSelectionState( JMapPane.NONE )}</li>
-     *   <li>{@code JMapPane.setState( JMapPane.Select )}</li>
-     *   <li>{@code JMapPane.setHighlight( true )}</li>
-     * </ol>
-     * @see JMapPane
-     * @param e das ActionEvent
-     */
-    public void actionPerformed(ActionEvent e) {
-      getMapPane().setWindowSelectionState( JMapPane.NONE );
-      getMapPane().setState(JMapPane.NONE);
-      getMapPane().setHighlight(true);
-    }
-  }
-
-  /**
-   * Aktion "Zoom" des {@link MapActionControlPane}.
-   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-   * @version 1.0
-   */
-  protected class Action_ZoomState extends AbstractAction {
-    /**
-     * Erzeugt einen neue Zoom-Aktion
-     */
-    public Action_ZoomState() {
-      super();
-      Icon icon = SwingUtil.createImageIconFromResourcePath("resource/icons/small/zoom.gif","ZoomIn");
-      this.putValue( SHORT_DESCRIPTION, GeotoolsGUIUtil.RESOURCE.getString( ZOOM_IN ) );
-      this.putValue( SMALL_ICON, icon );
-      if ( icon == null )
-        this.putValue( NAME, "ZoomIn" );
-    }
-
-    /**
-     * Fuehrt die Zoom-Aktion aus.
-     * <ol>
-     *   <li>{@code JMapPane.setWindowSelectionState( JMapPane.ZOOM )}</li>
-     *   <li>{@code JMapPane.setState( JMapPane.ZoomIn )}</li>
-     *   <li>{@code JMapPane.setHighlight( false )}</li>
-     * </ol>
-     * @see JMapPane
-     * @param e das ActionEvent
-     */
-    public void actionPerformed(ActionEvent e) {
-      getMapPane().setWindowSelectionState( JMapPane.ZOOM_IN );
-      getMapPane().setState(JMapPane.ZOOM_IN);
-      getMapPane().setHighlight(false);
-    }
-  }
-
-
-  /**
-   * Aktion "SelectTop" des {@link MapActionControlPane}.
-   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-   * @version 1.0
-   */
-  protected class Action_SelectOnTopLayerState extends AbstractAction {
-    /**
-     * Erzeugt einen neue SelectTop-Aktion
-     */
-    public Action_SelectOnTopLayerState() {
-      super();
-      Icon icon = SwingUtil.createImageIconFromResourcePath("resource/icons/small/select_normal.gif","SelectTop");
-      this.putValue( SHORT_DESCRIPTION, GeotoolsGUIUtil.RESOURCE.getString( SELECT_TOP ) );
-      this.putValue( SMALL_ICON, icon );
-      if ( icon == null )
-        this.putValue( NAME, "SelectTop" );
-    }
-
-    /**
-     * Fuehrt die SelectTop-Aktion aus.
-     * <ol>
-     *   <li>{@code JMapPane.setWindowSelectionState( JMapPane.SELECT_TOP )}</li>
-     *   <li>{@code JMapPane.setState( JMapPane.Select )}</li>
-     *   <li>{@code JMapPane.setHighlight( true )}</li>
-     * </ol>
-     * @see JMapPane
-     * @param e das ActionEvent
-     */
-    public void actionPerformed(ActionEvent e) {
-      getMapPane().setWindowSelectionState( JMapPane.SELECT_TOP );
-      getMapPane().setState(JMapPane.SELECT_TOP);
-      getMapPane().setHighlight(true);
-    }
-  }
-
-  /**
-   * Aktion "SelectAll" des {@link MapActionControlPane}.
-   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-   * @version 1.0
-   */
-  protected class Action_SelectOnAllLayerState extends AbstractAction {
-    /**
-     * Erzeugt einen neue SelectAll-Aktion
-     */
-    public Action_SelectOnAllLayerState() {
-      super();
-      Icon icon = SwingUtil.createImageIconFromResourcePath("resource/icons/small/select_multi.gif","SelectAll");
-      this.putValue( SHORT_DESCRIPTION, GeotoolsGUIUtil.RESOURCE.getString( SELECT_ALL ) );
-      this.putValue( SMALL_ICON, icon );
-      if ( icon == null )
-        this.putValue( NAME, "SelectAll" );
-    }
-
-    /**
-     * Fuehrt die SelectAll-Aktion aus.
-     * <ol>
-     *   <li>{@code JMapPane.setWindowSelectionState( JMapPane.SELECT_ALL )}</li>
-     *   <li>{@code JMapPane.setState( JMapPane.Select )}</li>
-     *   <li>{@code JMapPane.setHighlight( true )}</li>
-     * </ol>
-     * @see JMapPane
-     * @param e das ActionEvent
-     */
-    public void actionPerformed(ActionEvent e) {
-      getMapPane().setWindowSelectionState( JMapPane.SELECT_ALL );
-      getMapPane().setState(JMapPane.SELECT_ALL);
-      getMapPane().setHighlight(true);
-    }
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.gui;
+
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.util.Map;
+
+import javax.swing.AbstractAction;
+import javax.swing.ButtonGroup;
+import javax.swing.Icon;
+import javax.swing.JButton;
+import javax.swing.JToggleButton;
+import javax.swing.JToolBar;
+
+import schmitzm.geotools.map.event.FeatureSelectedEvent;
+import schmitzm.swing.CaptionsChangeable;
+import schmitzm.swing.SwingUtil;
+
+/**
+ * Diese Klasse stellt einen {@link JToolBar} dar, mit dem zwischen den
+ * verschiedenen "Klick"- und "Drag"-Aktionen des {@link JMapPane} gewechselt werden
+ * kann:
+ * <ul>
+ *   <li><b>Info:</b>
+ *       <ul>
+ *         <li>Links-Klick:  nichts</li>
+ *         <li>Links-Drag: nichts</li>
+ *         <li>Rechts-Klick: nichts</li>
+ *         <li>Rechts-Drag: Karten-Ausschnitt verschieben</li>
+ *       </ul></li>
+ *   <li><b>Zoom:</b>
+ *       <ul>
+ *         <li>Links-Klick:  Zoom in</li>
+ *         <li>Links-Drag: Zoom in auf selektierten Bereich</li>
+ *         <li>Rechts-Klick: Zoom out</li>
+ *         <li>Rechts-Drag: Karten-Ausschnitt verschieben</li>
+ *       </ul></li>
+ *   <li><b>SelectTop:</b><br>
+ *       Die Auswahl-Aktionen beziehen sich auf das oberste sichtbare Feature
+ *       und fuehren zu einem {@link FeatureSelectedEvent}:
+ *       <ul>
+ *         <li>Links-Klick: einzelnes Feature selektieren</li>
+ *         <li>Links-Drag: alle Features im selektierten Bereich auswaehlen</li>
+ *         <li>Rechts-Klick: nichts</li>
+ *         <li>Rechts-Drag: Karten-Ausschnitt verschieben</li>
+ *       </ul></li>
+ *   <li><b>SelectAll:</b><br>
+ *       Wie <i>SelectTop</i>. Die Auswahl-Aktionen beziehen sich jedoch auf
+ *       auf alle prinzipiell sichtbaren Layer (evt. verdeckte Features unterer
+ *       Layer werden auch ausgewaehlt!)
+ *       </li>
+ * </ul>
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class MapActionControlPane extends JToolBar implements CaptionsChangeable {
+  /** Konstante um die Aktion "Info" in der Mask der zur Verfuegung stehenden
+   *  Buttons anzusprechen. */
+  public static final int ACTION_INFO = 1;
+  /** Konstante um die Aktion "Zoom" in der Mask der zur Verfuegung stehenden
+   *  Buttons anzusprechen. */
+  public static final int ACTION_ZOOM_IN = 2;
+  /** Konstante um die Aktion "SelectAll" in der Mask der zur Verfuegung stehenden
+   *  Buttons anzusprechen. */
+  public static final int ACTION_SELECT_ALL = 4;
+  /** Konstante um die Aktion "SelectTop" in der Mask der zur Verfuegung stehenden
+   *  Buttons anzusprechen. */
+  public static final int ACTION_SELECT_TOP = 8;
+  /** Konstante um die ALLE Aktionen in der Mask der zur Verfuegung stehenden
+   *  Buttons anzusprechen. */
+  public static final int ACTION_ALL = 0xFFFFFFFF;
+
+  /** Key-Konstante um die Aktion "Info" anzusprechen.
+   *  @see #resetCaptions(Map) */
+  public static final String INFO = MapActionControlPane.class.getName()+".INFO";
+  /** Key-Konstante um die Aktion "Zoom" anzusprechen.
+   *  @see #resetCaptions(Map) */
+  public static final String ZOOM_IN = MapActionControlPane.class.getName()+".ZOOM_IN";
+  /** Key-Konstante um die Aktion "SelectAll" anzusprechen.
+   *  @see #resetCaptions(Map) */
+  public static final String SELECT_ALL = MapActionControlPane.class.getName()+".SELECT_ALL";
+  /** Key-Konstante um die Aktion "SelectTop" anzusprechen.
+   *  @see #resetCaptions(Map) */
+  public static final String SELECT_TOP = MapActionControlPane.class.getName()+".SELECT_TOP";
+
+
+  /** {@link JMapPane} das gesteuert wird. */
+  protected JMapPane mapPane = null;
+  /** Button fuer Info-Aktion. */
+  protected JToggleButton infoState = null;
+  /** Button fuer Zoom-Aktion. */
+  protected JToggleButton zoomState = null;
+  /** Button fuer SelectTop-Aktion. */
+  protected JToggleButton selectTopState = null;
+  /** Button fuer SelectAll-Aktion. */
+  protected JToggleButton selectAllState = null;
+  /** Maske, die die zur Verfuegung stehenden Aktionen codiert */
+  protected int actionMask = 0;
+
+  /**
+   * Erzeugt eine horizontale Steuer-Komponente, die (noch) keinem {@link JMapPane}
+   * zugeordnet ist.
+   */
+  public MapActionControlPane() {
+    this( null, HORIZONTAL );
+  }
+
+  /**
+   * Erzeugt eine horizontale Steuer-Komponente.
+   * @param mapPane {@link JMapPane} das gesteuert wird
+   */
+  public MapActionControlPane(JMapPane mapPane) {
+    this( mapPane, HORIZONTAL );
+  }
+
+  /**
+   * Erzeugt eine Steuer-Komponente.
+   * @param mapPane {@link JMapPane} das gesteuert wird
+   * @param orientation Orientierung der Komponente ({@link #HORIZONTAL}/{@link #VERTICAL})
+   * @param actionMask definiert, welche Aktionen (in Form von Buttons) angezeigt werden
+   *                   (OR-Verknuepfung der {@code ACTION}-Konstanten
+   */
+  public MapActionControlPane(JMapPane mapPane, int orientation, int actionMask) {
+    super(orientation);
+    this.actionMask = actionMask;
+    // Button erzeugen und in Gruppe einfuegen, damit immer nur
+    // eine aktiviert ist
+    infoState      = new JToggleButton( new Action_InfoState() );
+    zoomState      = new JToggleButton( new Action_ZoomState() );
+    selectTopState = new JToggleButton( new Action_SelectOnTopLayerState() );
+    selectAllState = new JToggleButton( new Action_SelectOnAllLayerState() );
+    ButtonGroup bGroup = new ButtonGroup();
+    bGroup.add(infoState);
+    bGroup.add(zoomState);
+    bGroup.add(selectTopState);
+    bGroup.add(selectAllState);
+    // Button dem ToolBar hinzufuegen
+    if ( isActionVisible(ACTION_INFO) )
+      this.add(infoState);
+    if ( isActionVisible(ACTION_ZOOM_IN) )
+      this.add(zoomState);
+    if ( isActionVisible(ACTION_SELECT_TOP) )
+      this.add(selectTopState);
+    if ( isActionVisible(ACTION_SELECT_ALL) )
+      this.add(selectAllState);
+
+    setMapPane(mapPane);
+  }
+
+  /**
+   * Erzeugt eine Steuer-Komponente. Alle Aktionen sind sichtbar.
+   * @param mapPane {@link JMapPane} das gesteuert wird
+   * @param orientation Orientierung der Komponente ({@link #HORIZONTAL}/{@link #VERTICAL})
+   */
+  public MapActionControlPane(JMapPane mapPane, int orientation) {
+    this(mapPane,orientation,ACTION_ALL);
+  }
+
+  /**
+   * Setzt die Aktivierung der Aktionen entsprechend den Einstellungen
+   * des {@code JMapPane}.
+   * @see JMapPane#getWindowSelectionState()
+   */
+  public void resetActions() {
+    for (int i=0; i<getComponentCount(); i++) {
+      Component comp = getComponent(i);
+      if ( comp instanceof JButton )
+        ((JButton)comp).setSelected(false);
+    }
+
+    // Buttons entsprechend dem MapPane-Status einstellen
+    infoState.doClick();
+    if ( mapPane != null ) {
+      switch( mapPane.getWindowSelectionState() ) {
+        case JMapPane.ZOOM_IN:     if ( isActionVisible(ACTION_ZOOM_IN) )
+                                     zoomState.doClick();
+                                   break;
+        case JMapPane.SELECT_TOP:  if ( isActionVisible(ACTION_SELECT_TOP) )
+                                     selectTopState.doClick();
+                                   break;
+        case JMapPane.SELECT_ALL:  if ( isActionVisible(ACTION_SELECT_ALL) )
+                                     selectAllState.doClick();
+                                   break;
+        case JMapPane.NONE:        if ( isActionVisible(ACTION_INFO) )
+                                     infoState.doClick();
+                                   break;
+      }
+    }
+  }
+
+  /**
+   * Prueft, ob eine Aktion (Button) zur Verfuegung steht.
+   * @param action Aktion codiert durch eine {@code ACTION}-Konstante
+   */
+  public boolean isActionVisible(int action) {
+    return (actionMask & action) > 0;
+  }
+
+  /**
+   * Setzt das {@link JMapPane}, das durch diese Komponente gesteuert wird.
+   */
+  public void setMapPane(JMapPane mapPane) {
+    this.mapPane = mapPane;
+    resetActions();
+  }
+
+  /**
+   * Liefert das {@link JMapPane}, das durch diese Komponente gesteuert wird.
+   */
+  public JMapPane getMapPane() {
+    return this.mapPane;
+  }
+
+  /**
+   * Belegt die Beschriftungen der Aktionen neu.
+   * @param newCaptions enhaelt die neuen Beschriftungen
+   * @see #INFO
+   * @see #ZOOM_IN
+   * @see #SELECT_TOP
+   * @see #SELECT_ALL
+   */
+  public void resetCaptions(Map<String,Object> newCaptions) {
+    if ( newCaptions == null )
+      return;
+    Object caption = newCaptions.get(INFO);
+    if ( caption != null )
+      infoState.getAction().putValue(AbstractAction.SHORT_DESCRIPTION,caption);
+    caption = newCaptions.get(ZOOM_IN);
+    if ( caption != null )
+      zoomState.getAction().putValue(AbstractAction.SHORT_DESCRIPTION,caption);
+    caption = newCaptions.get(SELECT_TOP);
+    if ( caption != null )
+      selectTopState.getAction().putValue(AbstractAction.SHORT_DESCRIPTION,caption);
+    caption = newCaptions.get(SELECT_ALL);
+    if ( caption != null )
+      selectAllState.getAction().putValue(AbstractAction.SHORT_DESCRIPTION,caption);
+  }
+
+  ///////////////////////////////////////////////////////////////////
+  /////////////////////   Button Aktionen   /////////////////////////
+  ///////////////////////////////////////////////////////////////////
+  /**
+   * Aktion "Info" des {@link MapActionControlPane}.
+   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+   * @version 1.0
+   */
+  protected class Action_InfoState extends AbstractAction {
+    /**
+     * Erzeugt einen neue Info-Aktion
+     */
+    public Action_InfoState() {
+      super();
+      Icon icon = SwingUtil.createImageIconFromResourcePath("resource/icons/small/info.gif","Info");
+      this.putValue( SHORT_DESCRIPTION, GeotoolsGUIUtil.RESOURCE.getString( INFO ) );
+      this.putValue( SMALL_ICON, icon );
+      if ( icon == null )
+        this.putValue( NAME, "Info" );
+    }
+
+    /**
+     * Fuehrt die Info-Aktion aus.
+     * <ol>
+     *   <li>{@code JMapPane.setWindowSelectionState( JMapPane.NONE )}</li>
+     *   <li>{@code JMapPane.setState( JMapPane.Select )}</li>
+     *   <li>{@code JMapPane.setHighlight( true )}</li>
+     * </ol>
+     * @see JMapPane
+     * @param e das ActionEvent
+     */
+    public void actionPerformed(ActionEvent e) {
+      getMapPane().setWindowSelectionState( JMapPane.NONE );
+      getMapPane().setState(JMapPane.NONE);
+      getMapPane().setHighlight(true);
+    }
+  }
+
+  /**
+   * Aktion "Zoom" des {@link MapActionControlPane}.
+   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+   * @version 1.0
+   */
+  protected class Action_ZoomState extends AbstractAction {
+    /**
+     * Erzeugt einen neue Zoom-Aktion
+     */
+    public Action_ZoomState() {
+      super();
+      Icon icon = SwingUtil.createImageIconFromResourcePath("resource/icons/small/zoom.gif","ZoomIn");
+      this.putValue( SHORT_DESCRIPTION, GeotoolsGUIUtil.RESOURCE.getString( ZOOM_IN ) );
+      this.putValue( SMALL_ICON, icon );
+      if ( icon == null )
+        this.putValue( NAME, "ZoomIn" );
+    }
+
+    /**
+     * Fuehrt die Zoom-Aktion aus.
+     * <ol>
+     *   <li>{@code JMapPane.setWindowSelectionState( JMapPane.ZOOM )}</li>
+     *   <li>{@code JMapPane.setState( JMapPane.ZoomIn )}</li>
+     *   <li>{@code JMapPane.setHighlight( false )}</li>
+     * </ol>
+     * @see JMapPane
+     * @param e das ActionEvent
+     */
+    public void actionPerformed(ActionEvent e) {
+      getMapPane().setWindowSelectionState( JMapPane.ZOOM_IN );
+      getMapPane().setState(JMapPane.ZOOM_IN);
+      getMapPane().setHighlight(false);
+    }
+  }
+
+
+  /**
+   * Aktion "SelectTop" des {@link MapActionControlPane}.
+   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+   * @version 1.0
+   */
+  protected class Action_SelectOnTopLayerState extends AbstractAction {
+    /**
+     * Erzeugt einen neue SelectTop-Aktion
+     */
+    public Action_SelectOnTopLayerState() {
+      super();
+      Icon icon = SwingUtil.createImageIconFromResourcePath("resource/icons/small/select_normal.gif","SelectTop");
+      this.putValue( SHORT_DESCRIPTION, GeotoolsGUIUtil.RESOURCE.getString( SELECT_TOP ) );
+      this.putValue( SMALL_ICON, icon );
+      if ( icon == null )
+        this.putValue( NAME, "SelectTop" );
+    }
+
+    /**
+     * Fuehrt die SelectTop-Aktion aus.
+     * <ol>
+     *   <li>{@code JMapPane.setWindowSelectionState( JMapPane.SELECT_TOP )}</li>
+     *   <li>{@code JMapPane.setState( JMapPane.Select )}</li>
+     *   <li>{@code JMapPane.setHighlight( true )}</li>
+     * </ol>
+     * @see JMapPane
+     * @param e das ActionEvent
+     */
+    public void actionPerformed(ActionEvent e) {
+      getMapPane().setWindowSelectionState( JMapPane.SELECT_TOP );
+      getMapPane().setState(JMapPane.SELECT_TOP);
+      getMapPane().setHighlight(true);
+    }
+  }
+
+  /**
+   * Aktion "SelectAll" des {@link MapActionControlPane}.
+   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+   * @version 1.0
+   */
+  protected class Action_SelectOnAllLayerState extends AbstractAction {
+    /**
+     * Erzeugt einen neue SelectAll-Aktion
+     */
+    public Action_SelectOnAllLayerState() {
+      super();
+      Icon icon = SwingUtil.createImageIconFromResourcePath("resource/icons/small/select_multi.gif","SelectAll");
+      this.putValue( SHORT_DESCRIPTION, GeotoolsGUIUtil.RESOURCE.getString( SELECT_ALL ) );
+      this.putValue( SMALL_ICON, icon );
+      if ( icon == null )
+        this.putValue( NAME, "SelectAll" );
+    }
+
+    /**
+     * Fuehrt die SelectAll-Aktion aus.
+     * <ol>
+     *   <li>{@code JMapPane.setWindowSelectionState( JMapPane.SELECT_ALL )}</li>
+     *   <li>{@code JMapPane.setState( JMapPane.Select )}</li>
+     *   <li>{@code JMapPane.setHighlight( true )}</li>
+     * </ol>
+     * @see JMapPane
+     * @param e das ActionEvent
+     */
+    public void actionPerformed(ActionEvent e) {
+      getMapPane().setWindowSelectionState( JMapPane.SELECT_ALL );
+      getMapPane().setState(JMapPane.SELECT_ALL);
+      getMapPane().setHighlight(true);
+    }
+  }
+
+}

Modified: trunk/src/schmitzm/geotools/gui/MapContextControlPane.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/MapContextControlPane.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/MapContextControlPane.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,619 +1,637 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.gui;
-
-import java.awt.Graphics;
-import java.awt.Window;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.util.Iterator;
-import java.util.Map;
-
-import javax.swing.BoxLayout;
-import javax.swing.JButton;
-import javax.swing.JCheckBox;
-import javax.swing.JCheckBoxMenuItem;
-import javax.swing.JDialog;
-import javax.swing.JMenu;
-import javax.swing.JMenuItem;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.event.MenuEvent;
-import javax.swing.event.MenuListener;
-
-import org.apache.log4j.Logger;
-import org.geotools.map.MapContext;
-import org.geotools.map.MapLayer;
-import org.geotools.map.event.MapLayerEvent;
-import org.geotools.map.event.MapLayerListEvent;
-import org.geotools.map.event.MapLayerListListener;
-import org.geotools.map.event.MapLayerListener;
-import org.geotools.styling.ColorMap;
-
-import schmitzm.geotools.grid.GridUtil;
-import schmitzm.geotools.map.event.MapLayerAdapter;
-import schmitzm.geotools.styling.ColorMapManager;
-import schmitzm.geotools.styling.StylingUtil;
-import schmitzm.lang.LangUtil;
-import schmitzm.swing.ButtonGroup;
-import schmitzm.swing.CaptionsChangeable;
-import schmitzm.swing.SwingUtil;
-import schmitzm.swing.event.WindowEventConnector;
-import schmitzm.swing.menu.ConnectedPopupMenu;
-
-
-/**
- * Diese Komponente ist an ein {@link JMapPane} gekoppelt und stellt die
- * dargestellten Layer in Form eine Liste dar.
- * @author Martin Schmitz
- * @version 1.0
- */
-public class MapContextControlPane extends JPanel {
-  protected final Logger LOGGER = LangUtil.createLogger(this);
-
-  /** Key, um den Menue-Eintrag "Move layer up" in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String MENU_MOVE_LAYER_UP = MapContextControlPane.class.getName()+".Menu.MOVE_UP";
-  /** Key, um den Menue-Eintrag "Move layer down" in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String MENU_MOVE_LAYER_DOWN = MapContextControlPane.class.getName()+".Menu.MOVE_DOWN";
-  /** Key, um den Menue-Eintrag "Zoom to layer" in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String MENU_ZOOM_TO_LAYER = MapContextControlPane.class.getName()+".Menu.ZOOM_TO";
-  /** Key, um den Menue-Eintrag "Feature-Filter..." in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String MENU_FILTER_LAYER = MapContextControlPane.class.getName()+".Menu.FILTER";
-  /** Key, um den Menue-Eintrag "Recolor..." in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String MENU_RECOLOR_LAYER = MapContextControlPane.class.getName()+".Menu.RECOLOR";
-  /** Key, um den Menue-Eintrag "Remove layer" in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String MENU_REMOVE_LAYER = MapContextControlPane.class.getName()+".Menu.REMOVE";
-  /** Key, um den Menue-Eintrag "Show all layers" in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String MENU_SHOW_ALL_LAYERS = MapContextControlPane.class.getName()+".Menu.SHOWALL";
-  /** Key, um den Menue-Eintrag "Hide all layers" in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String MENU_HIDE_ALL_LAYERS = MapContextControlPane.class.getName()+".Menu.HIDEALL";
-  /** Key, um den Menue-Eintrag "Invert all layers" in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String MENU_INVERT_ALL_LAYERS = MapContextControlPane.class.getName()+".Menu.INVERTALL";
-  /** Key, um den Unter-Menue-Eintrag "Customize color map" in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String MENU_CUSTOMIZE_COLOR = MapContextControlPane.class.getName()+".Menu.CUSTOMIZE";
-  /** Key, um den Titel des Farbpaletten-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String CM_DIALOG_TITLE = MapContextControlPane.class.getName()+".ColorMapDialog.TITLE";
-  /** Key, um den 1. Tabellenkopf-Eintrag "Quantity" des Farbpaletten-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String CM_DIALOG_TABLEHEADER_QUANTITY = ColorMapTable.TABLEHEADER_QUANTITY;
-  /** Key, um den 2. Tabellenkopf-Eintrag "Color" des Farbpaletten-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String CM_DIALOG_TABLEHEADER_COLOR = ColorMapTable.TABLEHEADER_COLOR;
-  /** Key, um den 3. Tabellenkopf-Eintrag "Label" des Farbpaletten-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String CM_DIALOG_TABLEHEADER_LABEL = ColorMapTable.TABLEHEADER_LABEL;
-  /** Key, um den OK-Button des Farbpaletten-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String CM_DIALOG_OK = MapContextControlPane.class.getName()+".ColorMapDialog.OK";
-  /** Key, um den ABBRECHEN-Button des Farbpaletten-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String CM_DIALOG_CANCEL = MapContextControlPane.class.getName()+".ColorMapDialog.CANCEL";
-  /** Key, um den SPEICHERN-Button des Farbpaletten-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String CM_DIALOG_SAVE = MapContextControlPane.class.getName()+".ColorMapDialog.SAVE";
-  /** Key, um den ÃœBERNEHMEN-Button des Farbpaletten-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String CM_DIALOG_APPLY = MapContextControlPane.class.getName()+".ColorMapDialog.APPLY";
-  /** Key, um den Titel des Farbpaletten-Speichern-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String CM_SAVE_DIALOG_TITLE = MapContextControlPane.class.getName()+".SaveColorMapDialog.TITLE";
-  /** Key, um den Text des Farbpaletten-Speichern-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String CM_SAVE_DIALOG_QUESTION = MapContextControlPane.class.getName()+".SaveColorMapDialog.QUESTION";
-  /** Key, um den Titel des FeatureCollection-Filter-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String FF_DIALOG_TITLE = FeatureLayerFilterDialog.DIALOG_TITLE;
-  /** Key, um das Attribute-Label des FeatureCollection-Filter-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String FF_DIALOG_ATTRIBUTE = FeatureCollectionFilterPanel.ATTRIBUTE_LABEL;
-  /** Key, um das Formel-Label des FeatureCollection-Filter-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String FF_DIALOG_RULE = FeatureCollectionFilterPanel.RULE_LABEL;
-  /** Key, um den Formel-Feld-Tooltip des FeatureCollection-Filter-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String FF_DIALOG_RULE_TOOLTIP = FeatureCollectionFilterPanel.RULE_TOOLTIP;
-  /** Key, um das Operatoren-Label des FeatureCollection-Filter-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String FF_DIALOG_OPERATORS = FeatureCollectionFilterPanel.OPERATOR_LABEL;
-  /** Key, um den Testen-Button des FeatureCollection-Filter-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String FF_DIALOG_TEST = FeatureCollectionFilterPanel.TEST_BUTTON;
-  /** Key, um den OK-Button des FeatureCollection-Filter-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String FF_DIALOG_OK = FeatureLayerFilterDialog.OK_BUTTON;
-  /** Key, um den ABBRECHEN-Button des FeatureCollection-Filter-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String FF_DIALOG_CANCEL = FeatureLayerFilterDialog.CANCEL_BUTTON;
-  /** Key, um den ÃœBERNEHMEN-Button des FeatureCollection-Filter-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
-  public static final String FF_DIALOG_APPLY = FeatureLayerFilterDialog.APPLY_BUTTON;
-
-  /** Karte, deren Layer kontrolliert werden. */
-  protected JMapPane        mapPane    = null;
-  /** Farbpaletten, die durch die Kontrolle zugewiesen werden koennen. */
-  private ColorMapManager colorMaps  = null;
-
-  /**
-   * Erzeugt eine neue Layer-Kontrolle.
-   * @param mapPane   Karten-Komponente, deren Layer kontrolliert wird
-   * @param colorMaps Raster-Farbpaletten, die durch die Kontrolle zugewiesen
-   *                  werden koennen
-   */
-  public MapContextControlPane(JMapPane mapPane, ColorMapManager colorMaps) {
-    super();
-//    this.parentFrame = SwingUtil.getParentWindow(this);
-    this.mapPane     = mapPane;
-    this.colorMaps   = colorMaps;
-
-    setLayout( new BoxLayout(this,BoxLayout.Y_AXIS) );
-    // Auf den MapContext lauschen und Steuerungskomponenten hinzufuegen,
-    // loeschen, verschieben
-    mapPane.getContext().addMapLayerListListener( new MapLayerListListener() {
-      public void layerAdded(MapLayerListEvent e) {
-        addLayerControl( getComponentCount()-e.getToIndex(), e.getLayer() );
-      }
-      public void layerChanged(MapLayerListEvent e) {
-        // Bezeichnung der Checkbox aendern
-        ((JCheckBox)getComponent( convertIndex(e.getFromIndex()) )).setText( e.getLayer().getTitle() );
-      }
-      public void layerMoved(MapLayerListEvent e) {
-        int from = convertIndex(e.getFromIndex());
-        int to   = convertIndex(e.getToIndex());
-        moveLayerControl( from, to );
-      }
-      public void layerRemoved(MapLayerListEvent e) {
-        int from = convertIndex(e.getFromIndex());
-        removeLayerControl( from );
-      }
-    });
-  }
-
-  /**
-   * Liefert die Farbpaletten, die durch die Kontroll-Komponente zugewiesen
-   * werden koennen.
-   */
-  public ColorMapManager getColorMapManager() {
-    return this.colorMaps;
-  }
-
-  /**
-   * Konvertiert einen Listen-Index des MapContext zu einem Index der
-   * MapContextControlList (oder layerObjects-Liste).
-   * Dies ist notwendig, da im MapContext der Index 0 fuer das unterste
-   * Layer steht, in der MapContextControlList (und layerObjects-Liste)
-   * jedoch fuer das oberste Layer!
-   */
-  private int convertIndex(int mapContextIdx) {
-    return getComponentCount()-1-mapContextIdx;
-  }
-
-  /**
-   * Fuegt eine neue Checkbox in die Liste der Kontroll-Komponenten ein
-   * @param idx   Stelle an der die Komponente eingefuegt wird (0 ist das oberste Layer)
-   * @param layer das neue Layer
-   */
-  private void addLayerControl(int idx, final MapLayer layer) {
-    MapLayerControl control = new MapLayerControl(layer);
-    add( control, idx );
-    validate();
-  }
-
-  /**
-   * Bewegt eine Kontroll-Komponente
-   * @param from Index der zu verschiebenden Komponente (0 ist die oberste)
-   * @param to   Index der Ziel-Position
-   */
-  private void moveLayerControl(int from, int to) {
-    JCheckBox cb = (JCheckBox)getComponent( from );
-    remove(cb);
-    add( cb, to );
-    validate();
-  }
-
-  /**
-   * Entfernt eine Kontroll-Komponente
-   * @param idx Index der zu loeschenden Komponente (0 ist die oberste)
-   */
-  private void removeLayerControl(int idx) {
-    remove(idx);
-    validate();
-    repaint();
-  }
-
-  //////////////////////////////////////////////////////////////////////////
-  // Kontext-Menue fuer Layer-Aktionen
-  //////////////////////////////////////////////////////////////////////////
-  private class MapLayerControl extends JCheckBox implements CaptionsChangeable, ActionListener {
-    private MapLayer  layer = null;
-    // Flag, ob bereits ein WindowListener im uebergeordneten Fenster
-    // eingetragen wurde (geschieht beim ersten Anzeigen)
-    private boolean windowListenerAdded = false;
-    // Menu-Items
-    private JMenuItem    moveLayerUp = null;
-    private JMenuItem    moveLayerDown = null;
-    private JMenuItem    zoomToLayer = null;
-    private JMenuItem    filterLayer = null;
-    private ColorMapMenu recolorLayer = null;
-    private JMenuItem    removeLayer = null;
-    private JMenuItem    showAllLayers = null;
-    private JMenuItem    hideAllLayers = null;
-    private JMenuItem    invertAllLayers = null;
-    private FeatureLayerFilterDialog filterDialog = null;
-
-    public MapLayerControl(final MapLayer layer) {
-      super( layer.getTitle(), layer.isVisible() );
-      this.layer = layer;
-      this.addActionListener( this ); // (un)check Checkbox
-
-      // Popup-Menue erzeugen, die die Funktionen des Layers steuert
-      final ConnectedPopupMenu menu = new ConnectedPopupMenu();
-      moveLayerUp     = new JMenuItem(GeotoolsGUIUtil.RESOURCE.getString(MENU_MOVE_LAYER_UP));
-      moveLayerDown   = new JMenuItem(GeotoolsGUIUtil.RESOURCE.getString(MENU_MOVE_LAYER_DOWN));
-      zoomToLayer     = new JMenuItem(GeotoolsGUIUtil.RESOURCE.getString(MENU_ZOOM_TO_LAYER));
-      filterLayer     = new JMenuItem(GeotoolsGUIUtil.RESOURCE.getString(MENU_FILTER_LAYER));
-      recolorLayer    = new ColorMapMenu(GeotoolsGUIUtil.RESOURCE.getString(MENU_RECOLOR_LAYER),layer);
-      removeLayer     = new JMenuItem(GeotoolsGUIUtil.RESOURCE.getString(MENU_REMOVE_LAYER));
-      showAllLayers   = new JMenuItem(GeotoolsGUIUtil.RESOURCE.getString(MENU_SHOW_ALL_LAYERS));
-      hideAllLayers   = new JMenuItem(GeotoolsGUIUtil.RESOURCE.getString(MENU_HIDE_ALL_LAYERS));
-      invertAllLayers = new JMenuItem(GeotoolsGUIUtil.RESOURCE.getString(MENU_INVERT_ALL_LAYERS));
-      moveLayerDown.addActionListener(this);
-      moveLayerUp.addActionListener(this);
-      zoomToLayer.addActionListener(this);
-      removeLayer.addActionListener(this);
-      showAllLayers.addActionListener(this);
-      hideAllLayers.addActionListener(this);
-      invertAllLayers.addActionListener(this);
-      filterLayer.addActionListener(this);
-      filterLayer.setEnabled( !JMapPane.isGridCoverageLayer(layer) );
-      if ( filterLayer.isEnabled() )
-        try {
-          filterDialog = new FeatureLayerFilterDialog(null,mapPane,layer);
-          filterDialog.setModal( false );
-        } catch (Exception err) {
-          LangUtil.logDebugError(LOGGER,"Layer "+layer.getTitle()+": FeatureFilterFrame could not be created!",err);
-          filterLayer.setEnabled(false);
-        }
-      menu.add( moveLayerUp );
-      menu.add( moveLayerDown );
-      menu.add( zoomToLayer );
-      menu.add( filterLayer );
-      menu.add( recolorLayer );
-      menu.addSeparator();
-      menu.add( removeLayer );
-      menu.addSeparator();
-      menu.add( showAllLayers );
-      menu.add( hideAllLayers );
-      menu.add( invertAllLayers );
-
-      menu.connectTo(this);
-
-      layer.addMapLayerListener( new MapLayerListener() {
-        public void layerChanged(MapLayerEvent e) {
-        }
-        public void layerHidden(MapLayerEvent e) {
-          setSelected( false );
-        }
-        public void layerShown(MapLayerEvent e) {
-          setSelected( true );
-        }
-      } );
-    }
-
-    /**
-     * Ruft die {@code super}-Methode auf. Zudem wird (beim ersten Anzeigen)
-     * ein {@link WindowEventConnector} in das uebergeordnete Fenster eingetragen,
-     * der dessen Aktionen mit denen des Feature-Filter-Fensters verbindet.
-     * @param g Graphics
-     */
-    public void paint(Graphics g) {
-      super.paint(g);
-      // Wenn das Fenster geschlossen/minimiert wird, soll auch das
-      // Feature-Filter-Fenster geschlossen/minimiert werden
-      if ( !windowListenerAdded && filterDialog != null ) {
-        Window parentFrame = SwingUtil.getParentWindow(this);
-        if ( parentFrame != null) {
-          parentFrame.addWindowListener(new WindowEventConnector(filterDialog));
-          windowListenerAdded = true;
-        }
-      }
-    }
-
-    /**
-     * Initiiert die Checkbox- und Menu-Aktionen, je nachdem, welche Quelle
-     * das ActionEvent hat.
-     * @param e ActionEvent
-     */
-    public void actionPerformed(ActionEvent e) {
-      if (e == null)
-        return;
-      Object source = e.getSource();
-      MapContext context = mapPane.getContext();
-      int        currIdx = context.indexOf(layer);
-
-      // Checkbox (un)checked -> (in)visible layer
-      if ( source == this )
-        layer.setVisible( !layer.isVisible() );
-      // Menu "Move layer up"
-      if ( source == moveLayerUp && currIdx + 1 < context.getLayerCount() )
-        context.moveLayer(currIdx, currIdx + 1);
-      // Menu "Move layer down"
-      if ( source == moveLayerDown && currIdx > 0)
-        context.moveLayer(currIdx, currIdx - 1);
-      // Menu "Zoom to layer"
-      if ( source == zoomToLayer )
-        mapPane.zoomToLayer(layer);
-      // Menu "Remove layer"
-      if ( source == removeLayer )
-        context.removeLayer(layer);
-      // Menu "Show all layer"
-      if ( source == showAllLayers )
-        for (MapLayer layer : context.getLayers() )
-          layer.setVisible( true );
-      // Menu "Hide all layer"
-      if ( source == hideAllLayers )
-        for (MapLayer layer : context.getLayers() )
-          layer.setVisible( false );
-      // Menu "Invert all layers"
-      if ( source == invertAllLayers )
-        for (MapLayer layer : context.getLayers() )
-          layer.setVisible( !layer.isVisible() );
-      // Menu "Filter layer"
-      if ( source == filterLayer ) {
-        filterDialog.toFront();
-        filterDialog.setVisible( true );
-      }
-      mapPane.refresh();
-    }
-
-    /**
-     * Belegt die Bezeichnungen der Menue-Eintraege neu.
-     * @param captionMap Map mit neuen Beschriftungen
-     */
-    public void resetCaptions(Map<String,Object> captionMap) {
-      SwingUtil.resetCaption ( moveLayerUp,     captionMap.get(MENU_MOVE_LAYER_UP) );
-      SwingUtil.resetCaption ( moveLayerDown,   captionMap.get(MENU_MOVE_LAYER_DOWN) );
-      SwingUtil.resetCaption ( zoomToLayer,     captionMap.get(MENU_ZOOM_TO_LAYER) );
-      SwingUtil.resetCaption ( recolorLayer,    captionMap.get(MENU_RECOLOR_LAYER) );
-      SwingUtil.resetCaption ( removeLayer,     captionMap.get(MENU_REMOVE_LAYER) );
-      SwingUtil.resetCaption ( showAllLayers,   captionMap.get(MENU_SHOW_ALL_LAYERS) );
-      SwingUtil.resetCaption ( hideAllLayers,   captionMap.get(MENU_HIDE_ALL_LAYERS) );
-      SwingUtil.resetCaption ( invertAllLayers, captionMap.get(MENU_INVERT_ALL_LAYERS) );
-      SwingUtil.resetCaption ( filterLayer,     captionMap.get(MENU_FILTER_LAYER) );
-      recolorLayer.resetCaptions(captionMap);
-      if ( filterDialog != null )
-        filterDialog.resetCaptions(captionMap);
-    }
-  }
-
-  //////////////////////////////////////////////////////////////////////////
-  // Menue fuer Farb-Paletten
-  //////////////////////////////////////////////////////////////////////////
-  private class ColorMapMenu extends JMenu implements CaptionsChangeable {
-    private MapLayer       layer             = null;
-    private ButtonGroup    menuItemGroup     = null;
-    // Flag, ob bereits ein WindowListener im uebergeordneten Fenster
-    // eingetragen wurde (geschieht beim ersten Anzeigen)
-    private boolean windowListenerAdded = false;
-    // statischer Menue-Eintrag zum Anpassen der Farbtabelle
-    private JMenuItem      customizeMenuItem = null;
-    // Button fuer Farbtabellen-Dialog (Instanzvariablen, damit
-    // Beschriftung geaendert werden kann!!)
-    private JButton okButton = null;
-    private JButton cancelButton = null;
-    private JButton applyButton = null;
-    private JButton saveButton = null;
-    // Farbtabellen-Dialog
-    private ColorMapTable  customiseDialogTable = new ColorMapTable();
-    private JDialog        customiseDialog      = null;
-    private String         cmDialogTitle         = GeotoolsGUIUtil.RESOURCE.getString(CM_DIALOG_TITLE);
-    private String         saveCMDialogTitle     = GeotoolsGUIUtil.RESOURCE.getString(CM_SAVE_DIALOG_TITLE);
-    private String         saveCMDialogQuestion  = GeotoolsGUIUtil.RESOURCE.getString(CM_SAVE_DIALOG_QUESTION);
-
-    /**
-     * Aktion, wenn eine der registrierten Farb-Paletten ausgewaehlt wird.
-     */
-    private ActionListener colorMapAction = new ActionListener() {
-      public void actionPerformed(ActionEvent e) {
-        String   colMapName = ((JCheckBoxMenuItem)e.getSource()).getText();
-        ColorMap colMap = (colMapName!=null) ? StylingUtil.cloneColorMap(colorMaps.get(colMapName)) : null;
-        if ( colMap != null ) {
-          layer.setStyle(GridUtil.createStyle(colMap, 1.0));
-          customiseDialogTable.setColorMap(colMap);
-          mapPane.setReset(true);
-          mapPane.repaint();
-          ((JCheckBoxMenuItem)e.getSource()).setSelected(true);
-        }
-      }
-    };
-
-    /**
-     * Aktion, um die aktuelle Farb-Paletten anzupassen.
-     */
-    private ActionListener customiseMapAction = new ActionListener() {
-      public void actionPerformed(ActionEvent e) {
-        if ( customiseDialog.isVisible() ) {
-          customiseDialog.toFront();
-          return;
-        }
-        customiseDialogTable.setColorMap( StylingUtil.cloneColorMap( StylingUtil.getColorMapFromStyle(layer.getStyle()) ) );
-        customiseDialog.setVisible(true);
-      }
-    };
-
-    /**
-     * Erzeugt ein neues Menue.
-     * @param desc  Beschreibung fuer das Menue
-     * @param layer Layer, das durch das Menue gesteuert wird
-     */
-    public ColorMapMenu(String desc, MapLayer layer) {
-      super(desc);
-      this.layer = layer;
-      this.customiseDialog = createColorMapDialog();
-      customizeMenuItem = new JMenuItem( GeotoolsGUIUtil.RESOURCE.getString(MENU_CUSTOMIZE_COLOR) );
-      customizeMenuItem.addActionListener( customiseMapAction );
-      // Initialer Aufbau
-      reorganise();
-      // Sobald das Menue neu angezeigt wird, muss es neu aufgebaut
-      // werden, wenn sich die vorgefertigten ColorMaps geaendert haben
-      this.addMenuListener( new MenuListener() {
-        private ColorMapManager oldColorMaps = (ColorMapManager)colorMaps.clone();
-        public void menuCanceled(MenuEvent e) {}
-        public void menuDeselected(MenuEvent e) {}
-        public void menuSelected(MenuEvent e) {
-          if ( !colorMaps.equals(oldColorMaps) ) {
-            reorganise();
-            oldColorMaps = (ColorMapManager)colorMaps.clone();
-          }
-        }
-      });
-    }
-
-    /**
-     * Baut das Menue neu auf.
-     */
-    public void reorganise() {
-      // Alle bisherigen Eintraege loeschen
-      this.removeAll();
-
-      // nur fuer GridCoverage2D-Objekte kann die Farbe veraendert werden
-//      FeatureTypeStyle[] fts = layer.getStyle().getFeatureTypeStyles();
-//      if ( !(fts[0].getRules()[0].getSymbolizers()[0] instanceof RasterSymbolizer) ) {
-      if ( !JMapPane.isGridCoverageLayer(layer) ) {
-        this.setEnabled(false);
-        return;
-      }
-
-      this.setEnabled(true);
-      this.menuItemGroup = new ButtonGroup();
-
-      // Einen Menue-Eintrag fuer jede registrierte Farb-Palette
-      Iterator<String> keys = colorMaps.keySet().iterator();
-      for (int i=0; keys.hasNext(); i++) {
-        String colMapName = keys.next();
-        JCheckBoxMenuItem item = new JCheckBoxMenuItem(colMapName);
-        item.addActionListener( colorMapAction );
-        menuItemGroup.add( item );
-        // Eintrag selektieren, wenn er vorher selektiert war
-        item.setSelected( StylingUtil.colorMapsEqual(
-            colorMaps.get(colMapName),
-            StylingUtil.getColorMapFromStyle(layer.getStyle())
-         ));
-        this.add( item );
-
-      }
-
-      // Einen Menue-Eintrag, um die Farb-Palette anzupassen
-      if ( this.getItemCount() > 0 )
-        this.addSeparator();
-      this.add( customizeMenuItem );
-    }
-
-    public void resetCaptions(Map<String,Object> captionMap) {
-      SwingUtil.resetCaption ( customizeMenuItem, captionMap.get(MENU_CUSTOMIZE_COLOR) );
-      SwingUtil.resetCaption ( okButton, captionMap.get(CM_DIALOG_OK) );
-      SwingUtil.resetCaption ( cancelButton, captionMap.get(CM_DIALOG_CANCEL) );
-      SwingUtil.resetCaption ( saveButton, captionMap.get(CM_DIALOG_SAVE) );
-      SwingUtil.resetCaption ( applyButton, captionMap.get(CM_DIALOG_APPLY) );
-      SwingUtil.resetCaption ( customiseDialog, captionMap.get(CM_DIALOG_TITLE) );
-
-      Object caption = captionMap.get( CM_DIALOG_TITLE );
-      if ( caption != null ) {
-        cmDialogTitle = caption.toString();
-        // Damit Layer-Bezeichnung in Titel uebernommen wird, ein MapLayerEvent
-        // ausloesen
-        layer.setTitle( layer.getTitle() );
-      }
-      caption = captionMap.get( CM_SAVE_DIALOG_TITLE );
-      if ( caption != null )
-        saveCMDialogTitle = caption.toString();
-      caption = captionMap.get( CM_SAVE_DIALOG_QUESTION );
-      if ( caption != null )
-        saveCMDialogQuestion = caption.toString();
-    }
-
-    /**
-     * Ruft die {@code super}-Methode auf. Zudem wird (beim ersten Anzeigen)
-     * ein {@link WindowEventConnector} in das uebergeordnete Fenster eingetragen,
-     * der dessen Aktionen mit denen des Farbpaletten-Fensters verbindet.
-     * @param g Graphics
-     */
-    public void paint(Graphics g) {
-      super.paint(g);
-      // Wenn das Fenster geschlossen/minimiert wird, soll auch das
-      // Farbpaletten-Fenster geschlossen/minimiert werden
-      if ( !windowListenerAdded ) {
-        Window parentFrame = SwingUtil.getParentWindow(this);
-        if ( parentFrame != null ) {
-          parentFrame.addWindowListener(new WindowEventConnector(customiseDialog));
-          windowListenerAdded = true;
-        }
-      }
-    }
-    /**
-     * Erzeugt einen Dialog, in dem die aktuelle Farb-Palette des (Raster-)
-     * Layers angezeigt wird und veraendert werden kann.
-     */
-    private JDialog createColorMapDialog() {
-      // Optionen des Dialogs (ActionListener folgen spaeter)
-      okButton = new JButton( SwingUtil.RESOURCE.getString("Ok") );
-      cancelButton = new JButton( SwingUtil.RESOURCE.getString("Cancel") );
-      applyButton = new JButton( SwingUtil.RESOURCE.getString("Apply") );
-      saveButton = new JButton( SwingUtil.RESOURCE.getString("Save") );
-      // Dialog aufbauen
-      JOptionPane pane = new JOptionPane(
-        new JScrollPane( customiseDialogTable ),
-        JOptionPane.QUESTION_MESSAGE,
-        JOptionPane.DEFAULT_OPTION,
-        null,
-        new JButton[] { okButton, cancelButton, applyButton, saveButton },
-        okButton
-      );
-      final JDialog dialog = pane.createDialog(SwingUtil.getParentWindow(this), cmDialogTitle + " ["+layer.getTitle()+"]");
-      dialog.setResizable(true);
-      dialog.setModal(false);
-      dialog.setSize(380,200);
-
-      // Aktionen der Farbpaletten-Fenster-Button
-      ActionListener action = new ActionListener() {
-        public void actionPerformed(ActionEvent e) {
-          // Ok- und Apply-Button > ColorMap uebernehmen
-          if ( e.getSource() == okButton || e.getSource() == applyButton ) {
-            // Farbe nur uebernehmen, wenn sich die Farb-Palette wirklich
-            // geaendert hat
-//            if ( !StylingUtil.colorMapsEqual(
-//                    customiseDialogTable.getColorMap(),
-//                    StylingUtil.getColorMapFromStyle(layer.getStyle()) ) ) {
-              layer.setStyle(GridUtil.createStyle( StylingUtil.cloneColorMap(customiseDialogTable.getColorMap()), 1.0));
-              mapPane.setReset(true);
-              mapPane.repaint();
-              menuItemGroup.setUnselected();
-//            }
-          }
-          // Ok- und Cancel-Button > Dialog schliessen
-          if ( e.getSource() == okButton || e.getSource() == cancelButton ) {
-            dialog.setVisible( false );
-          }
-          // Save-Button > Neue vordefinierte Palette erzeugen
-          if ( e.getSource() == saveButton ) {
-            String name = JOptionPane.showInputDialog(
-                MapContextControlPane.this,
-                saveCMDialogQuestion,
-                saveCMDialogTitle,
-                JOptionPane.QUESTION_MESSAGE
-            );
-            if ( name != null && !name.trim().equals("") ) {
-              colorMaps.put(name, StylingUtil.cloneColorMap(customiseDialogTable.getColorMap()));
-            }
-          }
-        }
-      };
-      okButton.addActionListener( action );
-      cancelButton.addActionListener( action );
-      applyButton.addActionListener( action );
-      saveButton.addActionListener( action );
-
-      // Wenn sich die die Bezeichnung des Layers aendert, soll auch der
-      // Titel des Farbpaletten-Fensters geaendert werden
-      layer.addMapLayerListener( new MapLayerAdapter() {
-        public void layerChanged(MapLayerEvent e) {
-          // Bezeichnung der Checkbox aendern
-         dialog.setTitle(cmDialogTitle + " ["+layer.getTitle()+"]");
-        }
-      });
-
-      return dialog;
-    }
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.gui;
+
+import java.awt.Graphics;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.swing.BoxLayout;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JDialog;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.event.MenuEvent;
+import javax.swing.event.MenuListener;
+
+import org.apache.log4j.Logger;
+import org.geotools.map.MapContext;
+import org.geotools.map.MapLayer;
+import org.geotools.map.event.MapLayerEvent;
+import org.geotools.map.event.MapLayerListEvent;
+import org.geotools.map.event.MapLayerListListener;
+import org.geotools.map.event.MapLayerListener;
+import org.geotools.styling.ColorMap;
+
+import schmitzm.geotools.grid.GridUtil;
+import schmitzm.geotools.map.event.MapLayerAdapter;
+import schmitzm.geotools.styling.ColorMapManager;
+import schmitzm.geotools.styling.StylingUtil;
+import schmitzm.lang.LangUtil;
+import schmitzm.swing.ButtonGroup;
+import schmitzm.swing.CaptionsChangeable;
+import schmitzm.swing.SwingUtil;
+import schmitzm.swing.event.WindowEventConnector;
+import schmitzm.swing.menu.ConnectedPopupMenu;
+
+
+/**
+ * Diese Komponente ist an ein {@link JMapPane} gekoppelt und stellt die
+ * dargestellten Layer in Form eine Liste dar.
+ * @author Martin Schmitz
+ * @version 1.0
+ */
+public class MapContextControlPane extends JPanel {
+  protected final Logger LOGGER = LangUtil.createLogger(this);
+
+  /** Key, um den Menue-Eintrag "Move layer up" in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String MENU_MOVE_LAYER_UP = MapContextControlPane.class.getName()+".Menu.MOVE_UP";
+  /** Key, um den Menue-Eintrag "Move layer down" in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String MENU_MOVE_LAYER_DOWN = MapContextControlPane.class.getName()+".Menu.MOVE_DOWN";
+  /** Key, um den Menue-Eintrag "Zoom to layer" in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String MENU_ZOOM_TO_LAYER = MapContextControlPane.class.getName()+".Menu.ZOOM_TO";
+  /** Key, um den Menue-Eintrag "Feature-Filter..." in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String MENU_FILTER_LAYER = MapContextControlPane.class.getName()+".Menu.FILTER";
+  /** Key, um den Menue-Eintrag "Recolor..." in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String MENU_RECOLOR_LAYER = MapContextControlPane.class.getName()+".Menu.RECOLOR";
+  /** Key, um den Menue-Eintrag "Remove layer" in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String MENU_REMOVE_LAYER = MapContextControlPane.class.getName()+".Menu.REMOVE";
+  /** Key, um den Menue-Eintrag "Show all layers" in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String MENU_SHOW_ALL_LAYERS = MapContextControlPane.class.getName()+".Menu.SHOWALL";
+  /** Key, um den Menue-Eintrag "Hide all layers" in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String MENU_HIDE_ALL_LAYERS = MapContextControlPane.class.getName()+".Menu.HIDEALL";
+  /** Key, um den Menue-Eintrag "Invert all layers" in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String MENU_INVERT_ALL_LAYERS = MapContextControlPane.class.getName()+".Menu.INVERTALL";
+  /** Key, um den Unter-Menue-Eintrag "Customize color map" in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String MENU_CUSTOMIZE_COLOR = MapContextControlPane.class.getName()+".Menu.CUSTOMIZE";
+  /** Key, um den Titel des Farbpaletten-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String CM_DIALOG_TITLE = MapContextControlPane.class.getName()+".ColorMapDialog.TITLE";
+  /** Key, um den 1. Tabellenkopf-Eintrag "Quantity" des Farbpaletten-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String CM_DIALOG_TABLEHEADER_QUANTITY = ColorMapTable.TABLEHEADER_QUANTITY;
+  /** Key, um den 2. Tabellenkopf-Eintrag "Color" des Farbpaletten-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String CM_DIALOG_TABLEHEADER_COLOR = ColorMapTable.TABLEHEADER_COLOR;
+  /** Key, um den 3. Tabellenkopf-Eintrag "Label" des Farbpaletten-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String CM_DIALOG_TABLEHEADER_LABEL = ColorMapTable.TABLEHEADER_LABEL;
+  /** Key, um den OK-Button des Farbpaletten-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String CM_DIALOG_OK = MapContextControlPane.class.getName()+".ColorMapDialog.OK";
+  /** Key, um den ABBRECHEN-Button des Farbpaletten-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String CM_DIALOG_CANCEL = MapContextControlPane.class.getName()+".ColorMapDialog.CANCEL";
+  /** Key, um den SPEICHERN-Button des Farbpaletten-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String CM_DIALOG_SAVE = MapContextControlPane.class.getName()+".ColorMapDialog.SAVE";
+  /** Key, um den ÃœBERNEHMEN-Button des Farbpaletten-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String CM_DIALOG_APPLY = MapContextControlPane.class.getName()+".ColorMapDialog.APPLY";
+  /** Key, um den Titel des Farbpaletten-Speichern-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String CM_SAVE_DIALOG_TITLE = MapContextControlPane.class.getName()+".SaveColorMapDialog.TITLE";
+  /** Key, um den Text des Farbpaletten-Speichern-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String CM_SAVE_DIALOG_QUESTION = MapContextControlPane.class.getName()+".SaveColorMapDialog.QUESTION";
+  /** Key, um den Titel des FeatureCollection-Filter-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String FF_DIALOG_TITLE = FeatureLayerFilterDialog.DIALOG_TITLE;
+  /** Key, um das Attribute-Label des FeatureCollection-Filter-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String FF_DIALOG_ATTRIBUTE = FeatureCollectionFilterPanel.ATTRIBUTE_LABEL;
+  /** Key, um das Formel-Label des FeatureCollection-Filter-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String FF_DIALOG_RULE = FeatureCollectionFilterPanel.RULE_LABEL;
+  /** Key, um den Formel-Feld-Tooltip des FeatureCollection-Filter-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String FF_DIALOG_RULE_TOOLTIP = FeatureCollectionFilterPanel.RULE_TOOLTIP;
+  /** Key, um das Operatoren-Label des FeatureCollection-Filter-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String FF_DIALOG_OPERATORS = FeatureCollectionFilterPanel.OPERATOR_LABEL;
+  /** Key, um den Testen-Button des FeatureCollection-Filter-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String FF_DIALOG_TEST = FeatureCollectionFilterPanel.TEST_BUTTON;
+  /** Key, um den OK-Button des FeatureCollection-Filter-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String FF_DIALOG_OK = FeatureLayerFilterDialog.OK_BUTTON;
+  /** Key, um den ABBRECHEN-Button des FeatureCollection-Filter-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String FF_DIALOG_CANCEL = FeatureLayerFilterDialog.CANCEL_BUTTON;
+  /** Key, um den ÃœBERNEHMEN-Button des FeatureCollection-Filter-Dialogs in der {@link CaptionsChangeable}-Map anzusprechen. */
+  public static final String FF_DIALOG_APPLY = FeatureLayerFilterDialog.APPLY_BUTTON;
+
+  /** Karte, deren Layer kontrolliert werden. */
+  protected JMapPane        mapPane    = null;
+  /** Farbpaletten, die durch die Kontrolle zugewiesen werden koennen. */
+  private ColorMapManager colorMaps  = null;
+
+  /**
+   * Erzeugt eine neue Layer-Kontrolle.
+   * @param mapPane   Karten-Komponente, deren Layer kontrolliert wird
+   * @param colorMaps Raster-Farbpaletten, die durch die Kontrolle zugewiesen
+   *                  werden koennen
+   */
+  public MapContextControlPane(JMapPane mapPane, ColorMapManager colorMaps) {
+    super();
+//    this.parentFrame = SwingUtil.getParentWindow(this);
+    this.mapPane     = mapPane;
+    this.colorMaps   = colorMaps;
+
+    setLayout( new BoxLayout(this,BoxLayout.Y_AXIS) );
+    // Auf den MapContext lauschen und Steuerungskomponenten hinzufuegen,
+    // loeschen, verschieben
+    mapPane.getContext().addMapLayerListListener( new MapLayerListListener() {
+      public void layerAdded(MapLayerListEvent e) {
+        addLayerControl( getComponentCount()-e.getToIndex(), e.getLayer() );
+      }
+      public void layerChanged(MapLayerListEvent e) {
+        // Bezeichnung der Checkbox aendern
+        ((JCheckBox)getComponent( convertIndex(e.getFromIndex()) )).setText( e.getLayer().getTitle() );
+      }
+      public void layerMoved(MapLayerListEvent e) {
+        int from = convertIndex(e.getFromIndex());
+        int to   = convertIndex(e.getToIndex());
+        moveLayerControl( from, to );
+      }
+      public void layerRemoved(MapLayerListEvent e) {
+        int from = convertIndex(e.getFromIndex());
+        removeLayerControl( from );
+      }
+    });
+  }
+
+  /**
+   * Liefert die Farbpaletten, die durch die Kontroll-Komponente zugewiesen
+   * werden koennen.
+   */
+  public ColorMapManager getColorMapManager() {
+    return this.colorMaps;
+  }
+
+  /**
+   * Konvertiert einen Listen-Index des MapContext zu einem Index der
+   * MapContextControlList (oder layerObjects-Liste).
+   * Dies ist notwendig, da im MapContext der Index 0 fuer das unterste
+   * Layer steht, in der MapContextControlList (und layerObjects-Liste)
+   * jedoch fuer das oberste Layer!
+   */
+  private int convertIndex(int mapContextIdx) {
+    return getComponentCount()-1-mapContextIdx;
+  }
+
+  /**
+   * Fuegt eine neue Checkbox in die Liste der Kontroll-Komponenten ein
+   * @param idx   Stelle an der die Komponente eingefuegt wird (0 ist das oberste Layer)
+   * @param layer das neue Layer
+   */
+  private void addLayerControl(int idx, final MapLayer layer) {
+    MapLayerControl control = new MapLayerControl(layer);
+    add( control, idx );
+    validate();
+  }
+
+  /**
+   * Bewegt eine Kontroll-Komponente
+   * @param from Index der zu verschiebenden Komponente (0 ist die oberste)
+   * @param to   Index der Ziel-Position
+   */
+  private void moveLayerControl(int from, int to) {
+    JCheckBox cb = (JCheckBox)getComponent( from );
+    remove(cb);
+    add( cb, to );
+    validate();
+  }
+
+  /**
+   * Entfernt eine Kontroll-Komponente
+   * @param idx Index der zu loeschenden Komponente (0 ist die oberste)
+   */
+  private void removeLayerControl(int idx) {
+    remove(idx);
+    validate();
+    repaint();
+  }
+
+  //////////////////////////////////////////////////////////////////////////
+  // Kontext-Menue fuer Layer-Aktionen
+  //////////////////////////////////////////////////////////////////////////
+  private class MapLayerControl extends JCheckBox implements CaptionsChangeable, ActionListener {
+    private MapLayer  layer = null;
+    // Flag, ob bereits ein WindowListener im uebergeordneten Fenster
+    // eingetragen wurde (geschieht beim ersten Anzeigen)
+    private boolean windowListenerAdded = false;
+    // Menu-Items
+    private JMenuItem    moveLayerUp = null;
+    private JMenuItem    moveLayerDown = null;
+    private JMenuItem    zoomToLayer = null;
+    private JMenuItem    filterLayer = null;
+    private ColorMapMenu recolorLayer = null;
+    private JMenuItem    removeLayer = null;
+    private JMenuItem    showAllLayers = null;
+    private JMenuItem    hideAllLayers = null;
+    private JMenuItem    invertAllLayers = null;
+    private FeatureLayerFilterDialog filterDialog = null;
+
+    public MapLayerControl(final MapLayer layer) {
+      super( layer.getTitle(), layer.isVisible() );
+      this.layer = layer;
+      this.addActionListener( this ); // (un)check Checkbox
+
+      // Popup-Menue erzeugen, die die Funktionen des Layers steuert
+      final ConnectedPopupMenu menu = new ConnectedPopupMenu();
+      moveLayerUp     = new JMenuItem(GeotoolsGUIUtil.RESOURCE.getString(MENU_MOVE_LAYER_UP));
+      moveLayerDown   = new JMenuItem(GeotoolsGUIUtil.RESOURCE.getString(MENU_MOVE_LAYER_DOWN));
+      zoomToLayer     = new JMenuItem(GeotoolsGUIUtil.RESOURCE.getString(MENU_ZOOM_TO_LAYER));
+      filterLayer     = new JMenuItem(GeotoolsGUIUtil.RESOURCE.getString(MENU_FILTER_LAYER));
+      recolorLayer    = new ColorMapMenu(GeotoolsGUIUtil.RESOURCE.getString(MENU_RECOLOR_LAYER),layer);
+      removeLayer     = new JMenuItem(GeotoolsGUIUtil.RESOURCE.getString(MENU_REMOVE_LAYER));
+      showAllLayers   = new JMenuItem(GeotoolsGUIUtil.RESOURCE.getString(MENU_SHOW_ALL_LAYERS));
+      hideAllLayers   = new JMenuItem(GeotoolsGUIUtil.RESOURCE.getString(MENU_HIDE_ALL_LAYERS));
+      invertAllLayers = new JMenuItem(GeotoolsGUIUtil.RESOURCE.getString(MENU_INVERT_ALL_LAYERS));
+      moveLayerDown.addActionListener(this);
+      moveLayerUp.addActionListener(this);
+      zoomToLayer.addActionListener(this);
+      removeLayer.addActionListener(this);
+      showAllLayers.addActionListener(this);
+      hideAllLayers.addActionListener(this);
+      invertAllLayers.addActionListener(this);
+      filterLayer.addActionListener(this);
+      filterLayer.setEnabled( !JMapPane.isGridCoverageLayer(layer) );
+      if ( filterLayer.isEnabled() )
+        try {
+          filterDialog = new FeatureLayerFilterDialog(null,mapPane,layer);
+          filterDialog.setModal( false );
+        } catch (Exception err) {
+          LangUtil.logDebugError(LOGGER,"Layer "+layer.getTitle()+": FeatureFilterFrame could not be created!",err);
+          filterLayer.setEnabled(false);
+        }
+      menu.add( moveLayerUp );
+      menu.add( moveLayerDown );
+      menu.add( zoomToLayer );
+      menu.add( filterLayer );
+      menu.add( recolorLayer );
+      menu.addSeparator();
+      menu.add( removeLayer );
+      menu.addSeparator();
+      menu.add( showAllLayers );
+      menu.add( hideAllLayers );
+      menu.add( invertAllLayers );
+
+      menu.connectTo(this);
+
+      layer.addMapLayerListener( new MapLayerListener() {
+        public void layerChanged(MapLayerEvent e) {
+        }
+        public void layerHidden(MapLayerEvent e) {
+          setSelected( false );
+        }
+        public void layerShown(MapLayerEvent e) {
+          setSelected( true );
+        }
+      } );
+    }
+
+    /**
+     * Ruft die {@code super}-Methode auf. Zudem wird (beim ersten Anzeigen)
+     * ein {@link WindowEventConnector} in das uebergeordnete Fenster eingetragen,
+     * der dessen Aktionen mit denen des Feature-Filter-Fensters verbindet.
+     * @param g Graphics
+     */
+    public void paint(Graphics g) {
+      super.paint(g);
+      // Wenn das Fenster geschlossen/minimiert wird, soll auch das
+      // Feature-Filter-Fenster geschlossen/minimiert werden
+      if ( !windowListenerAdded && filterDialog != null ) {
+        Window parentFrame = SwingUtil.getParentWindow(this);
+        if ( parentFrame != null) {
+          parentFrame.addWindowListener(new WindowEventConnector(filterDialog));
+          windowListenerAdded = true;
+        }
+      }
+    }
+
+    /**
+     * Initiiert die Checkbox- und Menu-Aktionen, je nachdem, welche Quelle
+     * das ActionEvent hat.
+     * @param e ActionEvent
+     */
+    public void actionPerformed(ActionEvent e) {
+      if (e == null)
+        return;
+      Object source = e.getSource();
+      MapContext context = mapPane.getContext();
+      int        currIdx = context.indexOf(layer);
+
+      // Checkbox (un)checked -> (in)visible layer
+      if ( source == this )
+        layer.setVisible( !layer.isVisible() );
+      // Menu "Move layer up"
+      if ( source == moveLayerUp && currIdx + 1 < context.getLayerCount() )
+        context.moveLayer(currIdx, currIdx + 1);
+      // Menu "Move layer down"
+      if ( source == moveLayerDown && currIdx > 0)
+        context.moveLayer(currIdx, currIdx - 1);
+      // Menu "Zoom to layer"
+      if ( source == zoomToLayer )
+        mapPane.zoomToLayer(layer);
+      // Menu "Remove layer"
+      if ( source == removeLayer )
+        context.removeLayer(layer);
+      // Menu "Show all layer"
+      if ( source == showAllLayers )
+        for (MapLayer layer : context.getLayers() )
+          layer.setVisible( true );
+      // Menu "Hide all layer"
+      if ( source == hideAllLayers )
+        for (MapLayer layer : context.getLayers() )
+          layer.setVisible( false );
+      // Menu "Invert all layers"
+      if ( source == invertAllLayers )
+        for (MapLayer layer : context.getLayers() )
+          layer.setVisible( !layer.isVisible() );
+      // Menu "Filter layer"
+      if ( source == filterLayer ) {
+        filterDialog.toFront();
+        filterDialog.setVisible( true );
+      }
+      mapPane.refresh();
+    }
+
+    /**
+     * Belegt die Bezeichnungen der Menue-Eintraege neu.
+     * @param captionMap Map mit neuen Beschriftungen
+     */
+    public void resetCaptions(Map<String,Object> captionMap) {
+      SwingUtil.resetCaption ( moveLayerUp,     captionMap.get(MENU_MOVE_LAYER_UP) );
+      SwingUtil.resetCaption ( moveLayerDown,   captionMap.get(MENU_MOVE_LAYER_DOWN) );
+      SwingUtil.resetCaption ( zoomToLayer,     captionMap.get(MENU_ZOOM_TO_LAYER) );
+      SwingUtil.resetCaption ( recolorLayer,    captionMap.get(MENU_RECOLOR_LAYER) );
+      SwingUtil.resetCaption ( removeLayer,     captionMap.get(MENU_REMOVE_LAYER) );
+      SwingUtil.resetCaption ( showAllLayers,   captionMap.get(MENU_SHOW_ALL_LAYERS) );
+      SwingUtil.resetCaption ( hideAllLayers,   captionMap.get(MENU_HIDE_ALL_LAYERS) );
+      SwingUtil.resetCaption ( invertAllLayers, captionMap.get(MENU_INVERT_ALL_LAYERS) );
+      SwingUtil.resetCaption ( filterLayer,     captionMap.get(MENU_FILTER_LAYER) );
+      recolorLayer.resetCaptions(captionMap);
+      if ( filterDialog != null )
+        filterDialog.resetCaptions(captionMap);
+    }
+  }
+
+  //////////////////////////////////////////////////////////////////////////
+  // Menue fuer Farb-Paletten
+  //////////////////////////////////////////////////////////////////////////
+  private class ColorMapMenu extends JMenu implements CaptionsChangeable {
+    private MapLayer       layer             = null;
+    private ButtonGroup    menuItemGroup     = null;
+    // Flag, ob bereits ein WindowListener im uebergeordneten Fenster
+    // eingetragen wurde (geschieht beim ersten Anzeigen)
+    private boolean windowListenerAdded = false;
+    // statischer Menue-Eintrag zum Anpassen der Farbtabelle
+    private JMenuItem      customizeMenuItem = null;
+    // Button fuer Farbtabellen-Dialog (Instanzvariablen, damit
+    // Beschriftung geaendert werden kann!!)
+    private JButton okButton = null;
+    private JButton cancelButton = null;
+    private JButton applyButton = null;
+    private JButton saveButton = null;
+    // Farbtabellen-Dialog
+    private ColorMapTable  customiseDialogTable = new ColorMapTable();
+    private JDialog        customiseDialog      = null;
+    private String         cmDialogTitle         = GeotoolsGUIUtil.RESOURCE.getString(CM_DIALOG_TITLE);
+    private String         saveCMDialogTitle     = GeotoolsGUIUtil.RESOURCE.getString(CM_SAVE_DIALOG_TITLE);
+    private String         saveCMDialogQuestion  = GeotoolsGUIUtil.RESOURCE.getString(CM_SAVE_DIALOG_QUESTION);
+
+    /**
+     * Aktion, wenn eine der registrierten Farb-Paletten ausgewaehlt wird.
+     */
+    private ActionListener colorMapAction = new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        String   colMapName = ((JCheckBoxMenuItem)e.getSource()).getText();
+        ColorMap colMap = (colMapName!=null) ? StylingUtil.cloneColorMap(colorMaps.get(colMapName)) : null;
+        if ( colMap != null ) {
+          layer.setStyle(GridUtil.createStyle(colMap, 1.0));
+          customiseDialogTable.setColorMap(colMap);
+          mapPane.setReset(true);
+          mapPane.repaint();
+          ((JCheckBoxMenuItem)e.getSource()).setSelected(true);
+        }
+      }
+    };
+
+    /**
+     * Aktion, um die aktuelle Farb-Paletten anzupassen.
+     */
+    private ActionListener customiseMapAction = new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        if ( customiseDialog.isVisible() ) {
+          customiseDialog.toFront();
+          return;
+        }
+        customiseDialogTable.setColorMap( StylingUtil.cloneColorMap( StylingUtil.getColorMapFromStyle(layer.getStyle()) ) );
+        customiseDialog.setVisible(true);
+      }
+    };
+
+    /**
+     * Erzeugt ein neues Menue.
+     * @param desc  Beschreibung fuer das Menue
+     * @param layer Layer, das durch das Menue gesteuert wird
+     */
+    public ColorMapMenu(String desc, MapLayer layer) {
+      super(desc);
+      this.layer = layer;
+      this.customiseDialog = createColorMapDialog();
+      customizeMenuItem = new JMenuItem( GeotoolsGUIUtil.RESOURCE.getString(MENU_CUSTOMIZE_COLOR) );
+      customizeMenuItem.addActionListener( customiseMapAction );
+      // Initialer Aufbau
+      reorganise();
+      // Sobald das Menue neu angezeigt wird, muss es neu aufgebaut
+      // werden, wenn sich die vorgefertigten ColorMaps geaendert haben
+      this.addMenuListener( new MenuListener() {
+        private ColorMapManager oldColorMaps = (ColorMapManager)colorMaps.clone();
+        public void menuCanceled(MenuEvent e) {}
+        public void menuDeselected(MenuEvent e) {}
+        public void menuSelected(MenuEvent e) {
+          if ( !colorMaps.equals(oldColorMaps) ) {
+            reorganise();
+            oldColorMaps = (ColorMapManager)colorMaps.clone();
+          }
+        }
+      });
+    }
+
+    /**
+     * Baut das Menue neu auf.
+     */
+    public void reorganise() {
+      // Alle bisherigen Eintraege loeschen
+      this.removeAll();
+
+      // nur fuer GridCoverage2D-Objekte kann die Farbe veraendert werden
+//      FeatureTypeStyle[] fts = layer.getStyle().getFeatureTypeStyles();
+//      if ( !(fts[0].getRules()[0].getSymbolizers()[0] instanceof RasterSymbolizer) ) {
+      if ( !JMapPane.isGridCoverageLayer(layer) ) {
+        this.setEnabled(false);
+        return;
+      }
+
+      this.setEnabled(true);
+      this.menuItemGroup = new ButtonGroup();
+
+      // Einen Menue-Eintrag fuer jede registrierte Farb-Palette
+      Iterator<String> keys = colorMaps.keySet().iterator();
+      for (int i=0; keys.hasNext(); i++) {
+        String colMapName = keys.next();
+        JCheckBoxMenuItem item = new JCheckBoxMenuItem(colMapName);
+        item.addActionListener( colorMapAction );
+        menuItemGroup.add( item );
+        // Eintrag selektieren, wenn er vorher selektiert war
+        item.setSelected( StylingUtil.colorMapsEqual(
+            colorMaps.get(colMapName),
+            StylingUtil.getColorMapFromStyle(layer.getStyle())
+         ));
+        this.add( item );
+
+      }
+
+      // Einen Menue-Eintrag, um die Farb-Palette anzupassen
+      if ( this.getItemCount() > 0 )
+        this.addSeparator();
+      this.add( customizeMenuItem );
+    }
+
+    public void resetCaptions(Map<String,Object> captionMap) {
+      SwingUtil.resetCaption ( customizeMenuItem, captionMap.get(MENU_CUSTOMIZE_COLOR) );
+      SwingUtil.resetCaption ( okButton, captionMap.get(CM_DIALOG_OK) );
+      SwingUtil.resetCaption ( cancelButton, captionMap.get(CM_DIALOG_CANCEL) );
+      SwingUtil.resetCaption ( saveButton, captionMap.get(CM_DIALOG_SAVE) );
+      SwingUtil.resetCaption ( applyButton, captionMap.get(CM_DIALOG_APPLY) );
+      SwingUtil.resetCaption ( customiseDialog, captionMap.get(CM_DIALOG_TITLE) );
+
+      Object caption = captionMap.get( CM_DIALOG_TITLE );
+      if ( caption != null ) {
+        cmDialogTitle = caption.toString();
+        // Damit Layer-Bezeichnung in Titel uebernommen wird, ein MapLayerEvent
+        // ausloesen
+        layer.setTitle( layer.getTitle() );
+      }
+      caption = captionMap.get( CM_SAVE_DIALOG_TITLE );
+      if ( caption != null )
+        saveCMDialogTitle = caption.toString();
+      caption = captionMap.get( CM_SAVE_DIALOG_QUESTION );
+      if ( caption != null )
+        saveCMDialogQuestion = caption.toString();
+    }
+
+    /**
+     * Ruft die {@code super}-Methode auf. Zudem wird (beim ersten Anzeigen)
+     * ein {@link WindowEventConnector} in das uebergeordnete Fenster eingetragen,
+     * der dessen Aktionen mit denen des Farbpaletten-Fensters verbindet.
+     * @param g Graphics
+     */
+    public void paint(Graphics g) {
+      super.paint(g);
+      // Wenn das Fenster geschlossen/minimiert wird, soll auch das
+      // Farbpaletten-Fenster geschlossen/minimiert werden
+      if ( !windowListenerAdded ) {
+        Window parentFrame = SwingUtil.getParentWindow(this);
+        if ( parentFrame != null ) {
+          parentFrame.addWindowListener(new WindowEventConnector(customiseDialog));
+          windowListenerAdded = true;
+        }
+      }
+    }
+    /**
+     * Erzeugt einen Dialog, in dem die aktuelle Farb-Palette des (Raster-)
+     * Layers angezeigt wird und veraendert werden kann.
+     */
+    private JDialog createColorMapDialog() {
+      // Optionen des Dialogs (ActionListener folgen spaeter)
+      okButton = new JButton( SwingUtil.RESOURCE.getString("Ok") );
+      cancelButton = new JButton( SwingUtil.RESOURCE.getString("Cancel") );
+      applyButton = new JButton( SwingUtil.RESOURCE.getString("Apply") );
+      saveButton = new JButton( SwingUtil.RESOURCE.getString("Save") );
+      // Dialog aufbauen
+      JOptionPane pane = new JOptionPane(
+        new JScrollPane( customiseDialogTable ),
+        JOptionPane.QUESTION_MESSAGE,
+        JOptionPane.DEFAULT_OPTION,
+        null,
+        new JButton[] { okButton, cancelButton, applyButton, saveButton },
+        okButton
+      );
+      final JDialog dialog = pane.createDialog(SwingUtil.getParentWindow(this), cmDialogTitle + " ["+layer.getTitle()+"]");
+      dialog.setResizable(true);
+      dialog.setModal(false);
+      dialog.setSize(380,200);
+
+      // Aktionen der Farbpaletten-Fenster-Button
+      ActionListener action = new ActionListener() {
+        public void actionPerformed(ActionEvent e) {
+          // Ok- und Apply-Button > ColorMap uebernehmen
+          if ( e.getSource() == okButton || e.getSource() == applyButton ) {
+            // Farbe nur uebernehmen, wenn sich die Farb-Palette wirklich
+            // geaendert hat
+//            if ( !StylingUtil.colorMapsEqual(
+//                    customiseDialogTable.getColorMap(),
+//                    StylingUtil.getColorMapFromStyle(layer.getStyle()) ) ) {
+              layer.setStyle(GridUtil.createStyle( StylingUtil.cloneColorMap(customiseDialogTable.getColorMap()), 1.0));
+              mapPane.setReset(true);
+              mapPane.repaint();
+              menuItemGroup.setUnselected();
+//            }
+          }
+          // Ok- und Cancel-Button > Dialog schliessen
+          if ( e.getSource() == okButton || e.getSource() == cancelButton ) {
+            dialog.setVisible( false );
+          }
+          // Save-Button > Neue vordefinierte Palette erzeugen
+          if ( e.getSource() == saveButton ) {
+            String name = JOptionPane.showInputDialog(
+                MapContextControlPane.this,
+                saveCMDialogQuestion,
+                saveCMDialogTitle,
+                JOptionPane.QUESTION_MESSAGE
+            );
+            if ( name != null && !name.trim().equals("") ) {
+              colorMaps.put(name, StylingUtil.cloneColorMap(customiseDialogTable.getColorMap()));
+            }
+          }
+        }
+      };
+      okButton.addActionListener( action );
+      cancelButton.addActionListener( action );
+      applyButton.addActionListener( action );
+      saveButton.addActionListener( action );
+
+      // Wenn sich die die Bezeichnung des Layers aendert, soll auch der
+      // Titel des Farbpaletten-Fensters geaendert werden
+      layer.addMapLayerListener( new MapLayerAdapter() {
+        public void layerChanged(MapLayerEvent e) {
+          // Bezeichnung der Checkbox aendern
+         dialog.setTitle(cmDialogTitle + " ["+layer.getTitle()+"]");
+        }
+      });
+
+      return dialog;
+    }
+  }
+}

Modified: trunk/src/schmitzm/geotools/gui/MapPaneStatusBar.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/MapPaneStatusBar.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/MapPaneStatusBar.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,90 +1,108 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.gui;
-
-import java.awt.BorderLayout;
-import java.awt.Color;
-import java.awt.Graphics;
-
-import javax.swing.SwingConstants;
-
-import schmitzm.swing.JPanel;
-
-/**
- * Stellt ein {@link BorderLayout}-Panel dar, in dem links ein
- * {@link RasterPositionLabel} und rechts ein {@link GeoPositionLabel}
- * dargestellt ist. Beide werden automatisch mit einem {@link JMapPane}
- * gekoppelt, so dass automatisch die Anzeige der Labels aktualisiert wird,
- * sobald sich der Cursor ueber die Karte bewegt.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class MapPaneStatusBar extends JPanel {
-  /** Zeigt die Raster-Koordinaten und den Rasterwert des obersten sichtbaren
-   *  Rasters an */
-  protected RasterPositionLabel rasterPositionLabel = null;
-  /** Zeigt die Welt-Koordinaten an */
-  protected GeoPositionLabel geoPositionLabel = null;
-
-  /**
-   * Erzeugt einen neuen Status-Balken.
-   * @param mapPane Karte mit der die Labels gekoppelt werden
-   */
-  public MapPaneStatusBar(JMapPane mapPane) {
-    this(mapPane,null,null);
-  }
-
-  /**
-   * Erzeugt einen neuen Status-Balken.
-   * @param mapPane Karte mit der die Labels gekoppelt werden
-   * @param rasterPosLabel Label, in dem die Raster-Koordinaten angezeigt
-   *        werden (wenn {@code null}, wird ein neues {@link RasterPositionLabel} erzeugt).
-   * @param geoPosLabel Label, in dem die Geo-Koordinaten angezeigt
-   *        werden (wenn {@code null}, wird ein neues {@link GeoPositionLabel} erzeugt).
-   */
-  public MapPaneStatusBar(JMapPane mapPane, RasterPositionLabel rasterPosLabel, GeoPositionLabel geoPosLabel) {
-    super();
-    setLayout( new BorderLayout() );
-    // rechts: Anzeige der aktuellen Welt-Koordinaten
-    this.geoPositionLabel = (geoPosLabel != null) ? geoPosLabel : new GeoPositionLabel(2);
-    geoPositionLabel.setHorizontalAlignment(SwingConstants.RIGHT);
-    geoPositionLabel.setFractionDigits(1);
-    this.add(geoPositionLabel,BorderLayout.EAST);
-    // links: Anzeige
-    rasterPositionLabel = (rasterPosLabel != null) ? rasterPosLabel : new RasterPositionLabel(2);
-    this.add(rasterPositionLabel,BorderLayout.WEST);
-
-    // Labels mit dem MapPane koppeln
-    mapPane.addMouseMotionListener(rasterPositionLabel);
-    mapPane.addMouseListener(geoPositionLabel);
-    mapPane.addMouseMotionListener(geoPositionLabel);
-  }
-  
-  /**
-   * Nuetzlich wenn die Componente gedruckt (z.B. wenn ein Screenshot gemacht wird) wird. Dann werden wird der
-   * Hintergrund auf WEISS gesetzt.
-   *
-   * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-   *         Kr&uuml;ger</a>
-   */
-  @Override
-  public void print(Graphics g) {
-      Color orig = getBackground();
-      setBackground(Color.WHITE);
-      // wrap in try/finally so that we always restore the state
-      try {
-          super.print(g);
-      } finally {
-          setBackground(orig);
-      }
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.gui;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Graphics;
+
+import javax.swing.SwingConstants;
+
+import schmitzm.swing.JPanel;
+
+/**
+ * Stellt ein {@link BorderLayout}-Panel dar, in dem links ein
+ * {@link RasterPositionLabel} und rechts ein {@link GeoPositionLabel}
+ * dargestellt ist. Beide werden automatisch mit einem {@link JMapPane}
+ * gekoppelt, so dass automatisch die Anzeige der Labels aktualisiert wird,
+ * sobald sich der Cursor ueber die Karte bewegt.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class MapPaneStatusBar extends JPanel {
+  /** Zeigt die Raster-Koordinaten und den Rasterwert des obersten sichtbaren
+   *  Rasters an */
+  protected RasterPositionLabel rasterPositionLabel = null;
+  /** Zeigt die Welt-Koordinaten an */
+  protected GeoPositionLabel geoPositionLabel = null;
+
+  /**
+   * Erzeugt einen neuen Status-Balken.
+   * @param mapPane Karte mit der die Labels gekoppelt werden
+   */
+  public MapPaneStatusBar(JMapPane mapPane) {
+    this(mapPane,null,null);
+  }
+
+  /**
+   * Erzeugt einen neuen Status-Balken.
+   * @param mapPane Karte mit der die Labels gekoppelt werden
+   * @param rasterPosLabel Label, in dem die Raster-Koordinaten angezeigt
+   *        werden (wenn {@code null}, wird ein neues {@link RasterPositionLabel} erzeugt).
+   * @param geoPosLabel Label, in dem die Geo-Koordinaten angezeigt
+   *        werden (wenn {@code null}, wird ein neues {@link GeoPositionLabel} erzeugt).
+   */
+  public MapPaneStatusBar(JMapPane mapPane, RasterPositionLabel rasterPosLabel, GeoPositionLabel geoPosLabel) {
+    super();
+    setLayout( new BorderLayout() );
+    // rechts: Anzeige der aktuellen Welt-Koordinaten
+    this.geoPositionLabel = (geoPosLabel != null) ? geoPosLabel : new GeoPositionLabel(2);
+    geoPositionLabel.setHorizontalAlignment(SwingConstants.RIGHT);
+    geoPositionLabel.setFractionDigits(1);
+    this.add(geoPositionLabel,BorderLayout.EAST);
+    // links: Anzeige
+    rasterPositionLabel = (rasterPosLabel != null) ? rasterPosLabel : new RasterPositionLabel(2);
+    this.add(rasterPositionLabel,BorderLayout.WEST);
+
+    // Labels mit dem MapPane koppeln
+    mapPane.addMouseMotionListener(rasterPositionLabel);
+    mapPane.addMouseListener(geoPositionLabel);
+    mapPane.addMouseMotionListener(geoPositionLabel);
+  }
+  
+  /**
+   * Nuetzlich wenn die Componente gedruckt (z.B. wenn ein Screenshot gemacht wird) wird. Dann werden wird der
+   * Hintergrund auf WEISS gesetzt.
+   *
+   * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+   *         Kr&uuml;ger</a>
+   */
+  @Override
+  public void print(Graphics g) {
+      Color orig = getBackground();
+      setBackground(Color.WHITE);
+      // wrap in try/finally so that we always restore the state
+      try {
+          super.print(g);
+      } finally {
+          setBackground(orig);
+      }
+  }
+}

Modified: trunk/src/schmitzm/geotools/gui/MouseSelectionTracker.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/MouseSelectionTracker.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/MouseSelectionTracker.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,117 +1,136 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.geotools.gui;
-
-import java.awt.event.MouseEvent;
-
-import org.geotools.gui.swing.MouseSelectionTracker_Public;
-
-/**
- * Extends the geotools {@link org.geotools.gui.swing.MouseSelectionTracker} with an
- * enable/disable functionality. 
- * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
- */
-public abstract class MouseSelectionTracker extends MouseSelectionTracker_Public {
-  /** Indicates whether the tracker reacts on mouse events. */
-  protected boolean enabled = true;
-
-  /**
-   * Returns whether the tracker reacts on mouse events or not.
-   */
-  public boolean isEnabled() {
-    return enabled;
-  }
-  
-  /**
-   * Sets whether the tracker reacts on mouse events or not.
-   */
-  public void setEnabled(boolean enabled) {
-    this.enabled = enabled;
-  }
-
-  /**
-   * Ignores the event if tracker is disabled. Otherwise the
-   * super method is called.
-   */
-  @Override
-  public void mouseClicked(MouseEvent e) {
-    if ( !isEnabled() )
-      return;
-    super.mouseClicked(e);
-  }
-
-  /**
-   * Ignores the event if tracker is disabled. Otherwise the
-   * super method is called.
-   */
-  @Override
-  public void mouseEntered(MouseEvent e) {
-    if ( !isEnabled() )
-      return;
-    super.mouseEntered(e);
-  }
-
-  /**
-   * Ignores the event if tracker is disabled. Otherwise the
-   * super method is called.
-   */
-  @Override
-  public void mouseExited(MouseEvent e) {
-    if ( !isEnabled() )
-      return;
-    super.mouseExited(e);
-  }
-  
-  /**
-   * Ignores the event if tracker is disabled. Otherwise the
-   * super method is called.
-   */
-  @Override
-  public void mousePressed(MouseEvent e) {
-    if ( !isEnabled() )
-      return;
-    super.mousePressed(e);
-  }
-
-  /**
-   * Ignores the event if tracker is disabled. Otherwise the
-   * super method is called.
-   */
-  @Override
-  public void mouseReleased(MouseEvent e) {
-    if ( !isEnabled() )
-      return;
-    super.mouseReleased(e);
-  }
-
-  /**
-   * Ignores the event if tracker is disabled. Otherwise the
-   * super method is called.
-   */
-  @Override
-  public void mouseDragged(MouseEvent e) {
-    if ( !isEnabled() )
-      return;
-    super.mouseDragged(e);
-  }
-
-  /**
-   * Ignores the event if tracker is disabled. Otherwise the
-   * super method is called.
-   */
-  @Override
-  public void mouseMoved(MouseEvent e) {
-    if ( !isEnabled() )
-      return;
-    super.mouseMoved(e);
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.gui;
+
+import java.awt.event.MouseEvent;
+
+import org.geotools.gui.swing.MouseSelectionTracker_Public;
+
+/**
+ * Extends the geotools {@link org.geotools.gui.swing.MouseSelectionTracker} with an
+ * enable/disable functionality. 
+ * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
+ */
+public abstract class MouseSelectionTracker extends MouseSelectionTracker_Public {
+  /** Indicates whether the tracker reacts on mouse events. */
+  protected boolean enabled = true;
+
+  /**
+   * Returns whether the tracker reacts on mouse events or not.
+   */
+  public boolean isEnabled() {
+    return enabled;
+  }
+  
+  /**
+   * Sets whether the tracker reacts on mouse events or not.
+   */
+  public void setEnabled(boolean enabled) {
+    this.enabled = enabled;
+  }
+
+  /**
+   * Ignores the event if tracker is disabled. Otherwise the
+   * super method is called.
+   */
+  @Override
+  public void mouseClicked(MouseEvent e) {
+    if ( !isEnabled() )
+      return;
+    super.mouseClicked(e);
+  }
+
+  /**
+   * Ignores the event if tracker is disabled. Otherwise the
+   * super method is called.
+   */
+  @Override
+  public void mouseEntered(MouseEvent e) {
+    if ( !isEnabled() )
+      return;
+    super.mouseEntered(e);
+  }
+
+  /**
+   * Ignores the event if tracker is disabled. Otherwise the
+   * super method is called.
+   */
+  @Override
+  public void mouseExited(MouseEvent e) {
+    if ( !isEnabled() )
+      return;
+    super.mouseExited(e);
+  }
+  
+  /**
+   * Ignores the event if tracker is disabled. Otherwise the
+   * super method is called.
+   */
+  @Override
+  public void mousePressed(MouseEvent e) {
+    if ( !isEnabled() )
+      return;
+    super.mousePressed(e);
+  }
+
+  /**
+   * Ignores the event if tracker is disabled. Otherwise the
+   * super method is called.
+   */
+  @Override
+  public void mouseReleased(MouseEvent e) {
+    if ( !isEnabled() )
+      return;
+    super.mouseReleased(e);
+  }
+
+  /**
+   * Ignores the event if tracker is disabled. Otherwise the
+   * super method is called.
+   */
+  @Override
+  public void mouseDragged(MouseEvent e) {
+    if ( !isEnabled() )
+      return;
+    super.mouseDragged(e);
+  }
+
+  /**
+   * Ignores the event if tracker is disabled. Otherwise the
+   * super method is called.
+   */
+  @Override
+  public void mouseMoved(MouseEvent e) {
+    if ( !isEnabled() )
+      return;
+    super.mouseMoved(e);
+  }
+
+}

Modified: trunk/src/schmitzm/geotools/gui/RasterPositionLabel.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/RasterPositionLabel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/RasterPositionLabel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,313 +1,331 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.gui;
-
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseMotionListener;
-import java.awt.geom.Point2D;
-import java.text.DecimalFormat;
-import java.util.Hashtable;
-import java.util.Map;
-
-import javax.swing.JLabel;
-
-import org.geotools.coverage.grid.GridCoverage2D;
-import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader;
-import org.geotools.geometry.GeneralDirectPosition;
-import org.geotools.map.MapLayer;
-import org.geotools.referencing.CRS;
-import org.opengis.referencing.operation.MathTransform;
-
-import schmitzm.data.WritableGrid;
-import schmitzm.geotools.grid.GridUtil;
-import schmitzm.swing.CaptionsChangeable;
-
-/**
- * Diese Klasse stellt ein {@link JLabel} dar, in dem (2dimensionale)
- * Raster-Koordinaten und der Rasterwert an der entsprechenden Stelle angezeigt
- * werden.<br>
- * Die Klasse fungiert als {@link MouseMotionListener} und kann so direkt an ein
- * {@link JMapPane} gekoppelt werden. Die Koordinaten-Darstellung im Label
- * aktualisiert sich somit automatisch, sobald sich die Maus ueber die Karte
- * bewegt.
- *
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- *         (University of Bonn/Germany)
- * @version 1.1
- *
- *          SK 01.09.07: finals fuer Variablen eingefuegt... die Funktion
- *          displayCoordinates() wird oft benutzt und es gab viele Variablen,
- *          die nie geaendert wurden.
- */
-public class RasterPositionLabel extends JLabel implements MouseMotionListener,
-		CaptionsChangeable {
-
-	// Faktor mit dem die Koordinaten vor dem Runden multipliziert und nach
-	// dem Runden dividiert werden
-	// --> bestimmt die dargestellten Nachkommastellen
-	private double fracFactor = 0.0;
-
-	/** Speichert das Format fuer die dargstellten Koordinaten */
-	protected DecimalFormat decForm = new DecimalFormat();
-	/**
-	 * Key, um das Label-Praefix in der {@link CaptionsChangeable}-Map
-	 * anzusprechen.
-	 *
-	 * @see #resetCaptions(Map)
-	 */
-	public static final String LABEL_PREFIX = RasterPositionLabel.class
-			.getName()
-			+ ".LABEL_PREFIX";
-	/**
-	 * Praefix, das der Raster-Position vorangestellt wird.
-	 *
-	 * @see #setLabelPrefix(String)
-	 */
-	public static String labelPrefix = GeotoolsGUIUtil.RESOURCE
-			.getString(LABEL_PREFIX);
-
-	/**
-	 * Erzeugt ein neues Label. Der Raster-Wert wird ohne Nachkommastellen
-	 * dargestellt.
-	 */
-	public RasterPositionLabel() {
-		this(0);
-	}
-
-	/**
-	 * Erzeugt ein neues Label.
-	 *
-	 * @param fracDigits
-	 *            Anzahl an Nachkommastellen, auf der Rasterwert gerundet wird
-	 */
-	public RasterPositionLabel(final int fracDigits) {
-		super(" ");
-		// eine Stelle vor dem Komma soll immer dargestellt werden
-		this.decForm.setMinimumIntegerDigits(1);
-		// Nachkommastellen setzen
-		this.setFractionDigits(fracDigits);
-	}
-
-	/**
-	 * Stellt die Koordinaten und den Wert des obersten (sichtbaren) Rasters im
-	 * Label dar, wenn das Event von einem {@link JMapPane} ausgeloest wurde.<br>
-	 * Wird {@link #mouseMoved(MouseEvent)} und
-	 * {@link #mouseDragged(MouseEvent)} aufgerufen.
-	 */
-	protected void displayCoordinates(final MouseEvent e) {
-		if (e == null || !(e.getSource() instanceof JMapPane))
-			return;
-
-		final JMapPane mapPane = (JMapPane) e.getSource();
-		// oberstes dargestelltes Raster suchen
-		final MapLayer layer = determineRasterLayer(mapPane);
-		if (layer == null) {
-			setText("");
-			return;
-		}
-		// Objekt aus Layer herausholen
-		final Object layerObj = JMapPane.getLayerSourceObject(layer);
-		if ((layerObj == null)
-				|| (!(layerObj instanceof GridCoverage2D) && !(layerObj instanceof org.geotools.coverage.grid.io.AbstractGridCoverage2DReader)))
-			return;
-
-		final StringBuffer valueStr = new StringBuffer();
-		if (layerObj instanceof GridCoverage2D) {
-			final GridCoverage2D gc = (GridCoverage2D) layerObj;
-			double[] gcValue = new double[0];
-			final GeneralDirectPosition actPos_GridCRS = new GeneralDirectPosition(
-					2);
-			try {
-				// Welt-Koordinaten der Mausposition ermitteln (in CRS der Map)
-				final Point2D actPos_MapCRS = JMapPane
-						.getMapCoordinatesFromEvent(e);
-				if (actPos_MapCRS == null)
-					return;
-				// Koordinaten in CRS des Rasters umrechnen
-				final MathTransform mapToGrid = CRS.findMathTransform(mapPane
-						.getContext().getCoordinateReferenceSystem(), gc
-						.getCoordinateReferenceSystem());
-				mapToGrid.transform(new GeneralDirectPosition(actPos_MapCRS),
-						actPos_GridCRS);
-				// Wert im Raster ermitteln
-				gcValue = gc.evaluate(actPos_GridCRS.toPoint2D(),
-						(double[]) null);
-			} catch (final Exception err) {
-				// Position out of Raster data
-			}
-
-			valueStr.append(labelPrefix == null ? "" : labelPrefix);
-			// Raster-Koordinaten anzeigen
-			int cellX = 0;
-			int cellY = 0;
-			if (gc instanceof WritableGrid) {
-				// Bei einem WritableGrid koennen diese automatisch ermittelt
-				// werden
-				final WritableGrid wg = (WritableGrid) gc;
-				cellX = wg
-						.convertRealToRaster(actPos_GridCRS.getOrdinate(0), 0);
-				cellY = wg
-						.convertRealToRaster(actPos_GridCRS.getOrdinate(1), 1);
-			} else {
-				// sonst: Raster-Koordinaten ausrechnen
-				final int cell[] = GridUtil.convertRealToRaster(gc,
-						actPos_GridCRS.getCoordinates());
-				cellX = cell[0];
-				cellY = cell[1];
-			}
-			valueStr.append(" (").append(cellX).append("/").append(cellY)
-					.append(")");
-
-			valueStr.append(": ");
-			for (int j = 0; j < gcValue.length; j++) {
-				if (j > 0)
-					valueStr.append(" / ");
-                valueStr.append(Double.isNaN(gcValue[j]) ? gcValue[j] : decForm
-                    .format(gcValue[j]));
-                //Debug: ungerundeten Raster-Wert anzeigen
-                //valueStr.append("   Orig = " + gcValue[j]);
-			}
-		}
-
-		// CHANGE SK 9.8.2008 START
-
-		else if (layerObj instanceof org.geotools.coverage.grid.io.AbstractGridCoverage2DReader) {
-			final GeneralDirectPosition actPos_GridCRS = new GeneralDirectPosition(
-					2);
-			try {
-				// Welt-Koordinaten der Mausposition ermitteln (in CRS der Map)
-				final Point2D actPos_MapCRS = JMapPane
-						.getMapCoordinatesFromEvent(e);
-				if (actPos_MapCRS == null)
-					return;
-				AbstractGridCoverage2DReader gcr = (AbstractGridCoverage2DReader) layerObj;
-				// Koordinaten in CRS des Rasters umrechnen
-				final MathTransform mapToGrid = CRS.findMathTransform(mapPane
-						.getContext().getCoordinateReferenceSystem(), gcr
-						.getCrs());
-				mapToGrid.transform(new GeneralDirectPosition(actPos_MapCRS),
-						actPos_GridCRS);
-				// Wert im Raster ermitteln
-				Hashtable<MapLayer, double[]> foundGridCoverageValues = mapPane
-						.findGridCoverageValues(actPos_GridCRS.toPoint2D(),
-								JMapPane.SELECT_ALL);
-				if (foundGridCoverageValues != null
-						&& foundGridCoverageValues.size() > 0) {
-					double[] gcValue = foundGridCoverageValues.values()
-							.iterator().next();
-					for (int j = 0; j < gcValue.length; j++) {
-						if (j > 0)
-							valueStr.append(" / ");
-						valueStr.append(Double.isNaN(gcValue[j]) ? gcValue[j]
-								: decForm.format(gcValue[j]));
-					}
-				}
-			} catch (final Exception err) {
-				// Position out of Raster data
-			}
-
-			// CHANGE SK 9.8.2008 END
-		}
-
-		// Text im Label anzeigen
-		setText(valueStr.toString());
-	}
-
-	/**
-	 * Ermittelt das Raster-Layer, dessen Koordinaten angezeigt werden.
-	 * Standardmaessig wird das oberste sichtbare Raster-Layer zurueckgegeben.
-	 * Sub-Klassen koennen diese Methode ueberschreiben, um ein anderes Layer zu
-	 * verwenden.
-	 *
-	 * @param mapPane
-	 *            MapPane der angezeigten Layer.
-	 */
-	protected MapLayer determineRasterLayer(final JMapPane mapPane) {
-		return mapPane.getTopVisibleGridCoverageLayer();
-	}
-
-	/**
-	 * Setzt den String, welcher der Rasterposition und dem Rasterwert
-	 * vorangestellt wird.
-	 *
-	 * @param label
-	 *            neues Praefix
-	 */
-	public void setLabelPrefix(final String label) {
-		labelPrefix = (label == null) ? "" : label;
-	}
-
-	/**
-	 * Liefert den String, welcher der Rasterposition und dem Rasterwert
-	 * vorangestellt wird.
-	 */
-	public String getLabelPrefix() {
-		return labelPrefix;
-	}
-
-	/**
-	 * Setzt das Label-Praefix neu, sofern in der Map ein Wert fuer
-	 * {@link #LABEL_PREFIX} hinterlegt ist.
-	 *
-	 * @param captionMap
-	 *            neue Labels
-	 */
-	public void resetCaptions(final Map<String, Object> captionMap) {
-		if (!captionMap.containsKey(LABEL_PREFIX))
-			return;
-		final Object newPrefix = captionMap.get(LABEL_PREFIX);
-		setLabelPrefix(newPrefix == null ? null : newPrefix.toString());
-	}
-
-	/**
-	 * Setzt die Anzahl an Nachkommastellen, die fuer den Rasterwert dargestellt
-	 * werden
-	 *
-	 * @param fracDigits
-	 *            Anzahl an Nachkommastellen
-	 */
-	public void setFractionDigits(final int fracDigits) {
-		this.fracFactor = Math.pow(10.0, fracDigits);
-		this.decForm.setMinimumFractionDigits(fracDigits);
-		this.decForm.setMaximumFractionDigits(fracDigits);
-	}
-
-	/**
-	 * Liefert die Anzahl an Nachkommastellen, die fuer den Rasterwert
-	 * dargestellt werden
-	 */
-	public int getFractionDigits() {
-		return (int) Math.log10(this.fracFactor);
-	}
-
-	/**
-	 * Wird aufgerufen, sobald die Maus bewegt wird. Stellt die Koordinaten und
-	 * den Rasterwert im Label dar, wenn das Event von einem {@link JMapPane}
-	 * ausgeloest wurde.
-	 *
-	 * @see #displayCoordinates(MouseEvent)
-	 */
-	public void mouseMoved(final MouseEvent e) {
-		displayCoordinates(e);
-	}
-
-	/**
-	 * Wird aufgerufen, sobald die Maus bei gedrueckter Taste bewegt wird.
-	 * Stellt die Koordinaten und den Rasterwert im Label dar, wenn das Event
-	 * von einem {@link JMapPane} ausgeloest wurde.
-	 *
-	 * @see #displayCoordinates(MouseEvent)
-	 */
-	public void mouseDragged(final MouseEvent e) {
-		displayCoordinates(e);
-	}
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.gui;
+
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionListener;
+import java.awt.geom.Point2D;
+import java.text.DecimalFormat;
+import java.util.Hashtable;
+import java.util.Map;
+
+import javax.swing.JLabel;
+
+import org.geotools.coverage.grid.GridCoverage2D;
+import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader;
+import org.geotools.geometry.GeneralDirectPosition;
+import org.geotools.map.MapLayer;
+import org.geotools.referencing.CRS;
+import org.opengis.referencing.operation.MathTransform;
+
+import schmitzm.data.WritableGrid;
+import schmitzm.geotools.grid.GridUtil;
+import schmitzm.swing.CaptionsChangeable;
+
+/**
+ * Diese Klasse stellt ein {@link JLabel} dar, in dem (2dimensionale)
+ * Raster-Koordinaten und der Rasterwert an der entsprechenden Stelle angezeigt
+ * werden.<br>
+ * Die Klasse fungiert als {@link MouseMotionListener} und kann so direkt an ein
+ * {@link JMapPane} gekoppelt werden. Die Koordinaten-Darstellung im Label
+ * aktualisiert sich somit automatisch, sobald sich die Maus ueber die Karte
+ * bewegt.
+ *
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *         (University of Bonn/Germany)
+ * @version 1.1
+ *
+ *          SK 01.09.07: finals fuer Variablen eingefuegt... die Funktion
+ *          displayCoordinates() wird oft benutzt und es gab viele Variablen,
+ *          die nie geaendert wurden.
+ */
+public class RasterPositionLabel extends JLabel implements MouseMotionListener,
+		CaptionsChangeable {
+
+	// Faktor mit dem die Koordinaten vor dem Runden multipliziert und nach
+	// dem Runden dividiert werden
+	// --> bestimmt die dargestellten Nachkommastellen
+	private double fracFactor = 0.0;
+
+	/** Speichert das Format fuer die dargstellten Koordinaten */
+	protected DecimalFormat decForm = new DecimalFormat();
+	/**
+	 * Key, um das Label-Praefix in der {@link CaptionsChangeable}-Map
+	 * anzusprechen.
+	 *
+	 * @see #resetCaptions(Map)
+	 */
+	public static final String LABEL_PREFIX = RasterPositionLabel.class
+			.getName()
+			+ ".LABEL_PREFIX";
+	/**
+	 * Praefix, das der Raster-Position vorangestellt wird.
+	 *
+	 * @see #setLabelPrefix(String)
+	 */
+	public static String labelPrefix = GeotoolsGUIUtil.RESOURCE
+			.getString(LABEL_PREFIX);
+
+	/**
+	 * Erzeugt ein neues Label. Der Raster-Wert wird ohne Nachkommastellen
+	 * dargestellt.
+	 */
+	public RasterPositionLabel() {
+		this(0);
+	}
+
+	/**
+	 * Erzeugt ein neues Label.
+	 *
+	 * @param fracDigits
+	 *            Anzahl an Nachkommastellen, auf der Rasterwert gerundet wird
+	 */
+	public RasterPositionLabel(final int fracDigits) {
+		super(" ");
+		// eine Stelle vor dem Komma soll immer dargestellt werden
+		this.decForm.setMinimumIntegerDigits(1);
+		// Nachkommastellen setzen
+		this.setFractionDigits(fracDigits);
+	}
+
+	/**
+	 * Stellt die Koordinaten und den Wert des obersten (sichtbaren) Rasters im
+	 * Label dar, wenn das Event von einem {@link JMapPane} ausgeloest wurde.<br>
+	 * Wird {@link #mouseMoved(MouseEvent)} und
+	 * {@link #mouseDragged(MouseEvent)} aufgerufen.
+	 */
+	protected void displayCoordinates(final MouseEvent e) {
+		if (e == null || !(e.getSource() instanceof JMapPane))
+			return;
+
+		final JMapPane mapPane = (JMapPane) e.getSource();
+		// oberstes dargestelltes Raster suchen
+		final MapLayer layer = determineRasterLayer(mapPane);
+		if (layer == null) {
+			setText("");
+			return;
+		}
+		// Objekt aus Layer herausholen
+		final Object layerObj = JMapPane.getLayerSourceObject(layer);
+		if ((layerObj == null)
+				|| (!(layerObj instanceof GridCoverage2D) && !(layerObj instanceof org.geotools.coverage.grid.io.AbstractGridCoverage2DReader)))
+			return;
+
+		final StringBuffer valueStr = new StringBuffer();
+		if (layerObj instanceof GridCoverage2D) {
+			final GridCoverage2D gc = (GridCoverage2D) layerObj;
+			double[] gcValue = new double[0];
+			final GeneralDirectPosition actPos_GridCRS = new GeneralDirectPosition(
+					2);
+			try {
+				// Welt-Koordinaten der Mausposition ermitteln (in CRS der Map)
+				final Point2D actPos_MapCRS = JMapPane
+						.getMapCoordinatesFromEvent(e);
+				if (actPos_MapCRS == null)
+					return;
+				// Koordinaten in CRS des Rasters umrechnen
+				final MathTransform mapToGrid = CRS.findMathTransform(mapPane
+						.getContext().getCoordinateReferenceSystem(), gc
+						.getCoordinateReferenceSystem());
+				mapToGrid.transform(new GeneralDirectPosition(actPos_MapCRS),
+						actPos_GridCRS);
+				// Wert im Raster ermitteln
+				gcValue = gc.evaluate(actPos_GridCRS.toPoint2D(),
+						(double[]) null);
+			} catch (final Exception err) {
+				// Position out of Raster data
+			}
+
+			valueStr.append(labelPrefix == null ? "" : labelPrefix);
+			// Raster-Koordinaten anzeigen
+			int cellX = 0;
+			int cellY = 0;
+			if (gc instanceof WritableGrid) {
+				// Bei einem WritableGrid koennen diese automatisch ermittelt
+				// werden
+				final WritableGrid wg = (WritableGrid) gc;
+				cellX = wg
+						.convertRealToRaster(actPos_GridCRS.getOrdinate(0), 0);
+				cellY = wg
+						.convertRealToRaster(actPos_GridCRS.getOrdinate(1), 1);
+			} else {
+				// sonst: Raster-Koordinaten ausrechnen
+				final int cell[] = GridUtil.convertRealToRaster(gc,
+						actPos_GridCRS.getCoordinates());
+				cellX = cell[0];
+				cellY = cell[1];
+			}
+			valueStr.append(" (").append(cellX).append("/").append(cellY)
+					.append(")");
+
+			valueStr.append(": ");
+			for (int j = 0; j < gcValue.length; j++) {
+				if (j > 0)
+					valueStr.append(" / ");
+                valueStr.append(Double.isNaN(gcValue[j]) ? gcValue[j] : decForm
+                    .format(gcValue[j]));
+                //Debug: ungerundeten Raster-Wert anzeigen
+                //valueStr.append("   Orig = " + gcValue[j]);
+			}
+		}
+
+		// CHANGE SK 9.8.2008 START
+
+		else if (layerObj instanceof org.geotools.coverage.grid.io.AbstractGridCoverage2DReader) {
+			final GeneralDirectPosition actPos_GridCRS = new GeneralDirectPosition(
+					2);
+			try {
+				// Welt-Koordinaten der Mausposition ermitteln (in CRS der Map)
+				final Point2D actPos_MapCRS = JMapPane
+						.getMapCoordinatesFromEvent(e);
+				if (actPos_MapCRS == null)
+					return;
+				AbstractGridCoverage2DReader gcr = (AbstractGridCoverage2DReader) layerObj;
+				// Koordinaten in CRS des Rasters umrechnen
+				final MathTransform mapToGrid = CRS.findMathTransform(mapPane
+						.getContext().getCoordinateReferenceSystem(), gcr
+						.getCrs());
+				mapToGrid.transform(new GeneralDirectPosition(actPos_MapCRS),
+						actPos_GridCRS);
+				// Wert im Raster ermitteln
+				Hashtable<MapLayer, double[]> foundGridCoverageValues = mapPane
+						.findGridCoverageValues(actPos_GridCRS.toPoint2D(),
+								JMapPane.SELECT_ALL);
+				if (foundGridCoverageValues != null
+						&& foundGridCoverageValues.size() > 0) {
+					double[] gcValue = foundGridCoverageValues.values()
+							.iterator().next();
+					for (int j = 0; j < gcValue.length; j++) {
+						if (j > 0)
+							valueStr.append(" / ");
+						valueStr.append(Double.isNaN(gcValue[j]) ? gcValue[j]
+								: decForm.format(gcValue[j]));
+					}
+				}
+			} catch (final Exception err) {
+				// Position out of Raster data
+			}
+
+			// CHANGE SK 9.8.2008 END
+		}
+
+		// Text im Label anzeigen
+		setText(valueStr.toString());
+	}
+
+	/**
+	 * Ermittelt das Raster-Layer, dessen Koordinaten angezeigt werden.
+	 * Standardmaessig wird das oberste sichtbare Raster-Layer zurueckgegeben.
+	 * Sub-Klassen koennen diese Methode ueberschreiben, um ein anderes Layer zu
+	 * verwenden.
+	 *
+	 * @param mapPane
+	 *            MapPane der angezeigten Layer.
+	 */
+	protected MapLayer determineRasterLayer(final JMapPane mapPane) {
+		return mapPane.getTopVisibleGridCoverageLayer();
+	}
+
+	/**
+	 * Setzt den String, welcher der Rasterposition und dem Rasterwert
+	 * vorangestellt wird.
+	 *
+	 * @param label
+	 *            neues Praefix
+	 */
+	public void setLabelPrefix(final String label) {
+		labelPrefix = (label == null) ? "" : label;
+	}
+
+	/**
+	 * Liefert den String, welcher der Rasterposition und dem Rasterwert
+	 * vorangestellt wird.
+	 */
+	public String getLabelPrefix() {
+		return labelPrefix;
+	}
+
+	/**
+	 * Setzt das Label-Praefix neu, sofern in der Map ein Wert fuer
+	 * {@link #LABEL_PREFIX} hinterlegt ist.
+	 *
+	 * @param captionMap
+	 *            neue Labels
+	 */
+	public void resetCaptions(final Map<String, Object> captionMap) {
+		if (!captionMap.containsKey(LABEL_PREFIX))
+			return;
+		final Object newPrefix = captionMap.get(LABEL_PREFIX);
+		setLabelPrefix(newPrefix == null ? null : newPrefix.toString());
+	}
+
+	/**
+	 * Setzt die Anzahl an Nachkommastellen, die fuer den Rasterwert dargestellt
+	 * werden
+	 *
+	 * @param fracDigits
+	 *            Anzahl an Nachkommastellen
+	 */
+	public void setFractionDigits(final int fracDigits) {
+		this.fracFactor = Math.pow(10.0, fracDigits);
+		this.decForm.setMinimumFractionDigits(fracDigits);
+		this.decForm.setMaximumFractionDigits(fracDigits);
+	}
+
+	/**
+	 * Liefert die Anzahl an Nachkommastellen, die fuer den Rasterwert
+	 * dargestellt werden
+	 */
+	public int getFractionDigits() {
+		return (int) Math.log10(this.fracFactor);
+	}
+
+	/**
+	 * Wird aufgerufen, sobald die Maus bewegt wird. Stellt die Koordinaten und
+	 * den Rasterwert im Label dar, wenn das Event von einem {@link JMapPane}
+	 * ausgeloest wurde.
+	 *
+	 * @see #displayCoordinates(MouseEvent)
+	 */
+	public void mouseMoved(final MouseEvent e) {
+		displayCoordinates(e);
+	}
+
+	/**
+	 * Wird aufgerufen, sobald die Maus bei gedrueckter Taste bewegt wird.
+	 * Stellt die Koordinaten und den Rasterwert im Label dar, wenn das Event
+	 * von einem {@link JMapPane} ausgeloest wurde.
+	 *
+	 * @see #displayCoordinates(MouseEvent)
+	 */
+	public void mouseDragged(final MouseEvent e) {
+		displayCoordinates(e);
+	}
+}

Modified: trunk/src/schmitzm/geotools/gui/ScalePane.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/ScalePane.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/ScalePane.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,112 +1,130 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.gui;
-
-import java.awt.Color;
-import java.awt.Graphics;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.text.DecimalFormat;
-
-import javax.swing.JLabel;
-
-import schmitzm.swing.JPanel;
-
-/**
- * Diese Klasse stellt einen Massstab-Balken ({@link ScalePanel}) und die
- * dazugehoerende Aufloesung in Metern pro Bildschirm-Pixel dar.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class ScalePane extends JPanel{
-  private static final DecimalFormat numFormat = new DecimalFormat("###,###,##0.00");
-
-  /** Massstab-Balken */
-  protected ScalePanel scalePanel  = null;
-  /** Label in dem die Aufloesung in Meter pro Pixel angezeigt wird. */
-  protected JLabel     scaleLabel  = new JLabel("");
-
-  /**
-   * Erzeugt eine Mass-Stab.
-   */
-  public ScalePane() {
-    super();
-    this.scalePanel = new ScalePanel();
-    setScale(1.0);
-    this.setLayout( new GridBagLayout() );
-    this.scaleLabel.setHorizontalAlignment(JLabel.LEFT);
-    this.add( scalePanel, new GridBagConstraints(0,0,2,1,1.0,1.0,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0) );
-    this.add( scaleLabel, new GridBagConstraints(0,1,1,1,0.5,0.0,GridBagConstraints.NORTHWEST,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0) );
-  }
-
-  /**
-   * Liefert die dargestellte Aufloesung in Pixel pro Meter.
-   */
-  public double getScaleInPixels() {
-    return scalePanel.getScaleInPixels();
-  }
-
-  /**
-   * Liefert die dargestellte Aufloesung in Metern pro Pixel.
-   */
-  public double getScaleInMeters() {
-    return scalePanel.getScaleInMeters();
-  }
-
-  /**
-   * Setzt die Aufloesung des Mass-Stabs und aktualisiert die Anzeige der
-   * Komponente.
-   * @param meters Meter, die durch einen Bildschirm-Pixel repraesentiert werden
-   */
-  public void setScale(double meters) {
-    scalePanel.setScale(meters);
-    scaleLabel.setText("1 pixel = "+numFormat.format(meters)+"m");
-    repaint();
-  }
-
-  /**
-   * Setzt die Aufloesung des Mass-Stabs und aktualisiert die Anzeige der
-   * Komponente.
-   * @param pixels Anzahl an Pixeln, die einen Meter repraesentieren werden
-   * @exception Ill
-   */
-  public void setScale(long pixels) {
-    scalePanel.setScale(pixels);
-    scaleLabel.setText(pixels+" pixel = 1m");
-    repaint();
-  }
-  
-  /**
-   * Nuetzlich wenn die Componente gedruckt (z.B. wenn ein Screenshot gemacht wird) wird. Dann werden wird der
-   * Hintergrund auf WEISS gesetzt.
-   *
-   * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-   *         Kr&uuml;ger</a>
-   */
-  @Override
-  public void print(Graphics g) {
-      final Color orig = getBackground();
-      setBackground(Color.WHITE);
-      // remove the informatil   xxx pixel = 1m
-      final String backupPixelText = scaleLabel.getText();
-      scaleLabel.setText("");
-      // wrap in try/finally so that we always restore the state
-      try {
-          super.print(g);
-      } finally {
-          setBackground(orig);
-          scaleLabel.setText(backupPixelText);
-      }
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.gui;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.text.DecimalFormat;
+
+import javax.swing.JLabel;
+
+import schmitzm.swing.JPanel;
+
+/**
+ * Diese Klasse stellt einen Massstab-Balken ({@link ScalePanel}) und die
+ * dazugehoerende Aufloesung in Metern pro Bildschirm-Pixel dar.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class ScalePane extends JPanel{
+  private static final DecimalFormat numFormat = new DecimalFormat("###,###,##0.00");
+
+  /** Massstab-Balken */
+  protected ScalePanel scalePanel  = null;
+  /** Label in dem die Aufloesung in Meter pro Pixel angezeigt wird. */
+  protected JLabel     scaleLabel  = new JLabel("");
+
+  /**
+   * Erzeugt eine Mass-Stab.
+   */
+  public ScalePane() {
+    super();
+    this.scalePanel = new ScalePanel();
+    setScale(1.0);
+    this.setLayout( new GridBagLayout() );
+    this.scaleLabel.setHorizontalAlignment(JLabel.LEFT);
+    this.add( scalePanel, new GridBagConstraints(0,0,2,1,1.0,1.0,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0) );
+    this.add( scaleLabel, new GridBagConstraints(0,1,1,1,0.5,0.0,GridBagConstraints.NORTHWEST,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0) );
+  }
+
+  /**
+   * Liefert die dargestellte Aufloesung in Pixel pro Meter.
+   */
+  public double getScaleInPixels() {
+    return scalePanel.getScaleInPixels();
+  }
+
+  /**
+   * Liefert die dargestellte Aufloesung in Metern pro Pixel.
+   */
+  public double getScaleInMeters() {
+    return scalePanel.getScaleInMeters();
+  }
+
+  /**
+   * Setzt die Aufloesung des Mass-Stabs und aktualisiert die Anzeige der
+   * Komponente.
+   * @param meters Meter, die durch einen Bildschirm-Pixel repraesentiert werden
+   */
+  public void setScale(double meters) {
+    scalePanel.setScale(meters);
+    scaleLabel.setText("1 pixel = "+numFormat.format(meters)+"m");
+    repaint();
+  }
+
+  /**
+   * Setzt die Aufloesung des Mass-Stabs und aktualisiert die Anzeige der
+   * Komponente.
+   * @param pixels Anzahl an Pixeln, die einen Meter repraesentieren werden
+   * @exception Ill
+   */
+  public void setScale(long pixels) {
+    scalePanel.setScale(pixels);
+    scaleLabel.setText(pixels+" pixel = 1m");
+    repaint();
+  }
+  
+  /**
+   * Nuetzlich wenn die Componente gedruckt (z.B. wenn ein Screenshot gemacht wird) wird. Dann werden wird der
+   * Hintergrund auf WEISS gesetzt.
+   *
+   * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+   *         Kr&uuml;ger</a>
+   */
+  @Override
+  public void print(Graphics g) {
+      final Color orig = getBackground();
+      setBackground(Color.WHITE);
+      // remove the informatil   xxx pixel = 1m
+      final String backupPixelText = scaleLabel.getText();
+      scaleLabel.setText("");
+      // wrap in try/finally so that we always restore the state
+      try {
+          super.print(g);
+      } finally {
+          setBackground(orig);
+          scaleLabel.setText(backupPixelText);
+      }
+  }
+
+}

Modified: trunk/src/schmitzm/geotools/gui/ScalePanel.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/ScalePanel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/ScalePanel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,122 +1,140 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.gui;
-
-import java.awt.Color;
-import java.awt.Graphics;
-import java.text.DecimalFormat;
-
-import javax.swing.JLabel;
-
-import schmitzm.swing.JPanel;
-import schmitzm.swing.SwingUtil;
-
-/**
- * Stellt einen horizontalen Massstab-Balken dar. Die dargestellte Breite
- * richtet sich nach der Groesse der Parent-Componente. Der Balken stellt immer
- * <b>volle</b> 10, 100, 1000, ... Meter dar.<br>
- * Diese Groesse wird rechts neben dem schwarz/weissen Balken angezeigt.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class ScalePanel extends JPanel {
-  private static final DecimalFormat numFormat = new DecimalFormat("###,###,##0");
-
-  /** Beinhaltet die aktuell dargestellte Aufloesung. Der Wert entspricht den
-   *  Metern, die durch einen Bildschirm-Pixel dargestellt werden.*/
-  protected double scale = 1;
-
-  /**
-   * Erzeugt eine Mass-Stab.
-   */
-  public ScalePanel() {
-    super();
-    SwingUtil.setPreferredHeight(this,10);
-  }
-
-  /**
-   * Liefert die dargestellte Aufloesung in Pixel pro Meter.
-   */
-  public double getScaleInPixels() {
-    return this.scale!=0 ? 1/this.scale : 0;
-  }
-
-  /**
-   * Liefert die dargestellte Aufloesung in Metern pro Pixel.
-   */
-  public double getScaleInMeters() {
-    return this.scale;
-  }
-
-  /**
-   * Setzt die Aufloesung des Mass-Stabs und aktualisiert die Anzeige der
-   * Komponente.
-   * @param meters Meter, die durch einen Bildschirm-Pixel repraesentiert werden
-   */
-  public void setScale(double meters) {
-    if ( meters <= 0 )
-      throw new IllegalArgumentException("Meters must be greater zero!");
-    this.scale = meters;
-    repaint();
-  }
-
-  /**
-   * Setzt die Aufloesung des Mass-Stabs und aktualisiert die Anzeige der
-   * Komponente.
-   * @param pixels Anzahl an Pixeln, die einen Meter repraesentieren werden
-   * @exception Ill
-   */
-  public void setScale(long pixels) {
-    if ( pixels <= 0 )
-      throw new IllegalArgumentException("Count of pixels must be greater zero!");
-    setScale(1.0/pixels);
-  }
-
-  /**
-   * Zeichnet den Massstab-Balken.
-   * @param g Graphics
-   */
-  public void paint(Graphics g) {
-    if (getParent() == null )
-      return;
-    super.paint(g);
-
-    // maximale Breite fuer Skala (abzgl. 25 Pixel fuer Meter-Angabe)
-    int    maxW_pixel    = getParent().getWidth() - 30;
-    double maxW_meter    = maxW_pixel * getScaleInMeters();
-    // Ausmasse der Skala (stellt immer volle 10/100/1000/... Meter dar)
-    long   scaleW_meter = (long)Math.pow(10, (long)Math.log10(maxW_meter));
-    int    scaleW_pixel = (int)Math.round( scaleW_meter * getScaleInPixels() );
-    int    scaleH_pixel = getHeight()-1;
-
-    // Aufteilung in der Skala Teil-Balken
-    int     tileScaleCount  = 4;
-    int     tileScaleWidth  = scaleW_pixel/tileScaleCount;
-    int     tileScaleHeight = scaleH_pixel;
-    Color[] barColor  = new Color[] { Color.BLACK, Color.WHITE };
-    int     nextColorIdx = 0;
-
-    // Teilbalken malen
-    for (int i = 0; i < tileScaleCount; i++) {
-      g.setColor(barColor[nextColorIdx]);
-      g.fillRect(i * tileScaleWidth, 0, tileScaleWidth, tileScaleHeight);
-      nextColorIdx = 1 - nextColorIdx;
-    }
-    // Rahmen um alle Balken
-    g.setColor(Color.BLACK);
-    g.drawRect(0, 0, tileScaleWidth*tileScaleCount, tileScaleHeight);
-    // Laengen-Angabe
-    g.setFont( new JLabel().getFont() );
-    String scaleString = scaleW_meter >= 1000 ? numFormat.format(scaleW_meter/1000)+"km" : numFormat.format(scaleW_meter)+"m";
-    g.drawString(scaleString,scaleW_pixel+3,tileScaleHeight);
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.gui;
+
+import java.awt.Color;
+import java.awt.Graphics;
+import java.text.DecimalFormat;
+
+import javax.swing.JLabel;
+
+import schmitzm.swing.JPanel;
+import schmitzm.swing.SwingUtil;
+
+/**
+ * Stellt einen horizontalen Massstab-Balken dar. Die dargestellte Breite
+ * richtet sich nach der Groesse der Parent-Componente. Der Balken stellt immer
+ * <b>volle</b> 10, 100, 1000, ... Meter dar.<br>
+ * Diese Groesse wird rechts neben dem schwarz/weissen Balken angezeigt.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class ScalePanel extends JPanel {
+  private static final DecimalFormat numFormat = new DecimalFormat("###,###,##0");
+
+  /** Beinhaltet die aktuell dargestellte Aufloesung. Der Wert entspricht den
+   *  Metern, die durch einen Bildschirm-Pixel dargestellt werden.*/
+  protected double scale = 1;
+
+  /**
+   * Erzeugt eine Mass-Stab.
+   */
+  public ScalePanel() {
+    super();
+    SwingUtil.setPreferredHeight(this,10);
+  }
+
+  /**
+   * Liefert die dargestellte Aufloesung in Pixel pro Meter.
+   */
+  public double getScaleInPixels() {
+    return this.scale!=0 ? 1/this.scale : 0;
+  }
+
+  /**
+   * Liefert die dargestellte Aufloesung in Metern pro Pixel.
+   */
+  public double getScaleInMeters() {
+    return this.scale;
+  }
+
+  /**
+   * Setzt die Aufloesung des Mass-Stabs und aktualisiert die Anzeige der
+   * Komponente.
+   * @param meters Meter, die durch einen Bildschirm-Pixel repraesentiert werden
+   */
+  public void setScale(double meters) {
+    if ( meters <= 0 )
+      throw new IllegalArgumentException("Meters must be greater zero!");
+    this.scale = meters;
+    repaint();
+  }
+
+  /**
+   * Setzt die Aufloesung des Mass-Stabs und aktualisiert die Anzeige der
+   * Komponente.
+   * @param pixels Anzahl an Pixeln, die einen Meter repraesentieren werden
+   * @exception Ill
+   */
+  public void setScale(long pixels) {
+    if ( pixels <= 0 )
+      throw new IllegalArgumentException("Count of pixels must be greater zero!");
+    setScale(1.0/pixels);
+  }
+
+  /**
+   * Zeichnet den Massstab-Balken.
+   * @param g Graphics
+   */
+  public void paint(Graphics g) {
+    if (getParent() == null )
+      return;
+    super.paint(g);
+
+    // maximale Breite fuer Skala (abzgl. 25 Pixel fuer Meter-Angabe)
+    int    maxW_pixel    = getParent().getWidth() - 30;
+    double maxW_meter    = maxW_pixel * getScaleInMeters();
+    // Ausmasse der Skala (stellt immer volle 10/100/1000/... Meter dar)
+    long   scaleW_meter = (long)Math.pow(10, (long)Math.log10(maxW_meter));
+    int    scaleW_pixel = (int)Math.round( scaleW_meter * getScaleInPixels() );
+    int    scaleH_pixel = getHeight()-1;
+
+    // Aufteilung in der Skala Teil-Balken
+    int     tileScaleCount  = 4;
+    int     tileScaleWidth  = scaleW_pixel/tileScaleCount;
+    int     tileScaleHeight = scaleH_pixel;
+    Color[] barColor  = new Color[] { Color.BLACK, Color.WHITE };
+    int     nextColorIdx = 0;
+
+    // Teilbalken malen
+    for (int i = 0; i < tileScaleCount; i++) {
+      g.setColor(barColor[nextColorIdx]);
+      g.fillRect(i * tileScaleWidth, 0, tileScaleWidth, tileScaleHeight);
+      nextColorIdx = 1 - nextColorIdx;
+    }
+    // Rahmen um alle Balken
+    g.setColor(Color.BLACK);
+    g.drawRect(0, 0, tileScaleWidth*tileScaleCount, tileScaleHeight);
+    // Laengen-Angabe
+    g.setFont( new JLabel().getFont() );
+    String scaleString = scaleW_meter >= 1000 ? numFormat.format(scaleW_meter/1000)+"km" : numFormat.format(scaleW_meter)+"m";
+    g.drawString(scaleString,scaleW_pixel+3,tileScaleHeight);
+  }
+}

Modified: trunk/src/schmitzm/geotools/gui/SelectableFeatureTablePane.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/SelectableFeatureTablePane.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/SelectableFeatureTablePane.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,13 +1,32 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package schmitzm.geotools.gui;
 
 import java.awt.BorderLayout;

Modified: trunk/src/schmitzm/geotools/gui/StyleToolBar.java
===================================================================
--- trunk/src/schmitzm/geotools/gui/StyleToolBar.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/StyleToolBar.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,255 +1,284 @@
-package schmitzm.geotools.gui;
-
-import java.awt.Color;
-import java.awt.Dimension;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-
-import javax.swing.JLabel;
-import javax.swing.JToolBar;
-
-import org.apache.log4j.Logger;
-import org.geotools.styling.Style;
-import org.geotools.styling.StyleBuilder;
-
-import schmitzm.geotools.feature.FeatureUtil;
-import schmitzm.swing.ColorInputOption;
-import schmitzm.swing.InputOption;
-import schmitzm.swing.SelectionInputOption;
-import schmitzm.swing.SwingUtil;
-import schmitzm.swing.event.InputOptionListener;
-
-/**
- * A toolbar to define simple parameters of a layer style.
- * <ul>
- *   <li>Fill color</li>
- *   <li>Border color</li>
- *   <li>Border width</li>
- *   <li>Mark style (dot, cross, ...)</li>
- *   <li>Mark size</li>
- * </ul>.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- */
-public class StyleToolBar extends JToolBar implements InputOptionListener {
-	protected static final Logger LOGGER = Logger.getLogger(JEditorToolBar.class.getName());
-	
-	private static final String RES_PREFIX = StyleToolBar.class.getName();
-     
-	/** Identifies the "fill color" (value type {@link Color}) for the
-	 *  {@link PropertyChangeListener}.
-	 *  @see #addPropertyChangeListener(PropertyChangeListener) */
-    public static final String FILL_COLOR = "Fill";
-    /** Identifies the "border color" (value type {@link Color}) for the
-     *  {@link PropertyChangeListener}.
-     *  @see #addPropertyChangeListener(PropertyChangeListener) */
-    public static final String BORDER_COLOR = "BorderColor";
-    /** Identifies the "border width" (value type {@code int}) for the
-     *  {@link PropertyChangeListener}.
-     *  @see #addPropertyChangeListener(PropertyChangeListener) */
-    public static final String BORDER_WIDTH = "BorderWidth";
-    /** Identifies the "mark style" (value type {@link String}) for the
-     *  {@link PropertyChangeListener}.
-     *  @see #addPropertyChangeListener(PropertyChangeListener) */
-    public static final String MARK_STYLE = "MarkStyle";
-    /** Identifies the "mark size" (value type {@link int}) for the
-     *  {@link PropertyChangeListener}.
-     *  @see #addPropertyChangeListener(PropertyChangeListener) */
-    public static final String MARK_SIZE = "MarkSize";
-	
-    /** Label next to the fill color {@link ColorInputOption InputOption}. */
-    protected JLabel fillColorLabel = null;
-    /** {@link InputOption} to define the fill color. */
-	protected ColorInputOption fillColor = null;
-    /** Label next to the border color {@link ColorInputOption InputOption}. */
-    protected JLabel borderColorLabel = null;
-    /** {@link InputOption} to define the border color. */
-	protected ColorInputOption borderColor = null;
-	/** Label next to the border width {@link SelectionInputOption InputOption}. */
-	protected JLabel borderWidthLabel = null;
-    /** {@link InputOption} to define the border width. */
-    protected SelectionInputOption.Combo<Integer> borderWidth = null;
-    /** Label next to the mark style and size {@link SelectionInputOption InputOptions}. */
-	protected JLabel markLabel = null;
-    /** {@link InputOption} to define the mark style. */
-	protected SelectionInputOption.Combo<String> markStyle = null;
-    /** {@link InputOption} to define the mark size. */
-    protected SelectionInputOption.Combo<Integer> markSize = null;
-
-    /**
-	 * Creates a new tool bar. Calls {@link #initGUI()}.
-	 */
-	public StyleToolBar() {
-	  super("Defines a style", JToolBar.HORIZONTAL);
-	  setFloatable(false);
-	  setRollover(true);
-	  initGUI();
-	}
-	
-	/**
-	 * Creates the GUI.
-	 */
-	protected void initGUI() {
-	  removeAll();
-	  
-	  //#####  Fill color  #####
-	  fillColorLabel = new JLabel( GeotoolsGUIUtil.RESOURCE.getString(RES_PREFIX+".FillColor") );
-      fillColor = new ColorInputOption(null,true,Color.RED);
-      fillColor.addInputOptionListener(this);
-      SwingUtil.setPreferredWidth(fillColor, 40);
-      SwingUtil.fixComponentSize(fillColor);
-      //##### Border color #####
-      borderColorLabel = new JLabel( GeotoolsGUIUtil.RESOURCE.getString(RES_PREFIX+".BorderColor") );
-      borderColor = new ColorInputOption(null,true,Color.BLACK);
-      borderColor.addInputOptionListener(this);
-      SwingUtil.setPreferredWidth(borderColor, 40);
-      SwingUtil.fixComponentSize(borderColor);
-      //##### Border width #####
-      borderWidthLabel = new JLabel( GeotoolsGUIUtil.RESOURCE.getString(RES_PREFIX+".BorderWidth") );
-      borderWidth = new SelectionInputOption.Combo<Integer>(
-          null,
-          true,
-          new Integer[] {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20},
-          (Integer)2,
-          null
-      );
-      borderWidth.addInputOptionListener(this);
-      SwingUtil.setPreferredWidth(borderWidth, 50);
-      SwingUtil.fixComponentSize(borderWidth);
-      //##### Mark style #####
-      markLabel = new JLabel( GeotoolsGUIUtil.RESOURCE.getString(RES_PREFIX+".PointMark") );
-      markStyle = new SelectionInputOption.Combo<String>(
-          null,
-          true,
-          new String[] {
-              StyleBuilder.MARK_ARROW, 
-              StyleBuilder.MARK_CIRCLE, 
-              StyleBuilder.MARK_CROSS,
-              StyleBuilder.MARK_SQUARE,
-              StyleBuilder.MARK_STAR,
-              StyleBuilder.MARK_TRIANGLE,
-              StyleBuilder.MARK_X
-          },
-          StyleBuilder.MARK_CIRCLE,
-          new String[] {
-              GeotoolsGUIUtil.RESOURCE.getString("org.geotools.styling.StyleBuilder.MARK_ARROW"),
-              GeotoolsGUIUtil.RESOURCE.getString("org.geotools.styling.StyleBuilder.MARK_CIRCLE"),
-              GeotoolsGUIUtil.RESOURCE.getString("org.geotools.styling.StyleBuilder.MARK_CROSS"),
-              GeotoolsGUIUtil.RESOURCE.getString("org.geotools.styling.StyleBuilder.MARK_SQUARE"),
-              GeotoolsGUIUtil.RESOURCE.getString("org.geotools.styling.StyleBuilder.MARK_STAR"),
-              GeotoolsGUIUtil.RESOURCE.getString("org.geotools.styling.StyleBuilder.MARK_TRIANGLE"),
-              GeotoolsGUIUtil.RESOURCE.getString("org.geotools.styling.StyleBuilder.MARK_X")
-          }
-      );
-      markStyle.addInputOptionListener(this);
-      SwingUtil.fixComponentSize(markStyle);
-      markSize = new SelectionInputOption.Combo<Integer>(
-          null,
-          true,
-          new Integer[] {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20},
-          (Integer)5,
-          null
-      );
-      markSize.addInputOptionListener(this);
-      SwingUtil.setPreferredWidth(markSize, 50);
-      SwingUtil.fixComponentSize(markSize);
-
-      //##### put the components to the tool bar #####
-      add( fillColorLabel );
-      addSeparator( new Dimension(2,0) );
-      add( fillColor );
-      addSeparator( new Dimension(10,0) );
-      add( borderColorLabel );
-      addSeparator( new Dimension(2,0) );
-      add( borderColor );
-      addSeparator( new Dimension(10,0) );
-      add( borderWidthLabel );
-      addSeparator( new Dimension(2,0) );
-      add( borderWidth );
-      addSeparator( new Dimension(10,0) );
-      add( markLabel );
-      addSeparator( new Dimension(2,0) );
-      add( markStyle );
-      addSeparator( new Dimension(2,0) );
-      add( markSize );
-	}
-	
-	/**
-	 * Creates a point style with the currently set point style, size, fill and
-	 * border color.
-	 */
-	public Style createPointStyle() {
-	  return FeatureUtil.createPointStyle(
-	      (String)markStyle.getValue(),
-	      fillColor.getValue(),
-	      borderColor.getValue(),
-	      1.0,
-	      1.0,
-	      ((Number)markSize.getValue()).doubleValue(),
-	      0.0
-	  );
-	}
-
-    /**
-     * Creates a line style with the currently set border color and
-     * width.
-     */
-    public Style createLineStyle() {
-      return FeatureUtil.createLineStyle(
-          borderColor.getValue(),
-          ((Number)borderWidth.getValue()).doubleValue()
-      );
-    }
-
-    /**
-     * Creates a polygon style with the currently set fill, border color and
-     * width.
-     */
-    public Style createPolygonStyle() {
-      return FeatureUtil.createPolygonStyle(
-          fillColor.getValue(),
-          borderColor.getValue(),
-          ((Number)borderWidth.getValue()).doubleValue()
-      );
-    }
-
-    /**
-     * Called whenever one of the input options of this tool bar
-     * has changed its value. Invokes a {@link PropertyChangeEvent}
-     * according to the changed input option.
-     * @see #FILL_COLOR
-     * @see #BORDER_COLOR
-     * @see #BORDER_WIDTH
-     * @see #MARK_STYLE
-     * @see #MARK_SIZE
-     */
-    public void optionChanged(InputOption option, Object oldValue, Object newValue) {
-      String changedProperty = null;
-      if ( option == fillColor )
-        changedProperty = FILL_COLOR;
-      if ( option == borderColor )
-        changedProperty = BORDER_COLOR;
-      if ( option == borderWidth )
-        changedProperty = BORDER_WIDTH;
-      if ( option == markStyle )
-        changedProperty = MARK_STYLE;
-      if ( option == markSize )
-        changedProperty = MARK_SIZE;
-      
-      if ( changedProperty != null )
-        firePropertyChange(changedProperty, oldValue, newValue);
-    }
-
-    /**
-     * Called whenever one of the input options of this tool bar
-     * lost focus. Does nothing.
-     */
-    public void optionLostFocus(InputOption option) {
-    }
-
-    /**
-     * Called whenever one of the input options of this tool bar
-     * gained focus. Does nothing.
-     */
-    public void optionGainedFocus(InputOption option) {}
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.gui;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import javax.swing.JLabel;
+import javax.swing.JToolBar;
+
+import org.apache.log4j.Logger;
+import org.geotools.styling.Style;
+import org.geotools.styling.StyleBuilder;
+
+import schmitzm.geotools.feature.FeatureUtil;
+import schmitzm.swing.ColorInputOption;
+import schmitzm.swing.InputOption;
+import schmitzm.swing.SelectionInputOption;
+import schmitzm.swing.SwingUtil;
+import schmitzm.swing.event.InputOptionListener;
+
+/**
+ * A toolbar to define simple parameters of a layer style.
+ * <ul>
+ *   <li>Fill color</li>
+ *   <li>Border color</li>
+ *   <li>Border width</li>
+ *   <li>Mark style (dot, cross, ...)</li>
+ *   <li>Mark size</li>
+ * </ul>.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ */
+public class StyleToolBar extends JToolBar implements InputOptionListener {
+	protected static final Logger LOGGER = Logger.getLogger(JEditorToolBar.class.getName());
+	
+	private static final String RES_PREFIX = StyleToolBar.class.getName();
+     
+	/** Identifies the "fill color" (value type {@link Color}) for the
+	 *  {@link PropertyChangeListener}.
+	 *  @see #addPropertyChangeListener(PropertyChangeListener) */
+    public static final String FILL_COLOR = "Fill";
+    /** Identifies the "border color" (value type {@link Color}) for the
+     *  {@link PropertyChangeListener}.
+     *  @see #addPropertyChangeListener(PropertyChangeListener) */
+    public static final String BORDER_COLOR = "BorderColor";
+    /** Identifies the "border width" (value type {@code int}) for the
+     *  {@link PropertyChangeListener}.
+     *  @see #addPropertyChangeListener(PropertyChangeListener) */
+    public static final String BORDER_WIDTH = "BorderWidth";
+    /** Identifies the "mark style" (value type {@link String}) for the
+     *  {@link PropertyChangeListener}.
+     *  @see #addPropertyChangeListener(PropertyChangeListener) */
+    public static final String MARK_STYLE = "MarkStyle";
+    /** Identifies the "mark size" (value type {@link int}) for the
+     *  {@link PropertyChangeListener}.
+     *  @see #addPropertyChangeListener(PropertyChangeListener) */
+    public static final String MARK_SIZE = "MarkSize";
+	
+    /** Label next to the fill color {@link ColorInputOption InputOption}. */
+    protected JLabel fillColorLabel = null;
+    /** {@link InputOption} to define the fill color. */
+	protected ColorInputOption fillColor = null;
+    /** Label next to the border color {@link ColorInputOption InputOption}. */
+    protected JLabel borderColorLabel = null;
+    /** {@link InputOption} to define the border color. */
+	protected ColorInputOption borderColor = null;
+	/** Label next to the border width {@link SelectionInputOption InputOption}. */
+	protected JLabel borderWidthLabel = null;
+    /** {@link InputOption} to define the border width. */
+    protected SelectionInputOption.Combo<Integer> borderWidth = null;
+    /** Label next to the mark style and size {@link SelectionInputOption InputOptions}. */
+	protected JLabel markLabel = null;
+    /** {@link InputOption} to define the mark style. */
+	protected SelectionInputOption.Combo<String> markStyle = null;
+    /** {@link InputOption} to define the mark size. */
+    protected SelectionInputOption.Combo<Integer> markSize = null;
+
+    /**
+	 * Creates a new tool bar. Calls {@link #initGUI()}.
+	 */
+	public StyleToolBar() {
+	  super("Defines a style", JToolBar.HORIZONTAL);
+	  setFloatable(false);
+	  setRollover(true);
+	  initGUI();
+	}
+	
+	/**
+	 * Creates the GUI.
+	 */
+	protected void initGUI() {
+	  removeAll();
+	  
+	  //#####  Fill color  #####
+	  fillColorLabel = new JLabel( GeotoolsGUIUtil.RESOURCE.getString(RES_PREFIX+".FillColor") );
+      fillColor = new ColorInputOption(null,true,Color.RED);
+      fillColor.addInputOptionListener(this);
+      SwingUtil.setPreferredWidth(fillColor, 40);
+      SwingUtil.fixComponentSize(fillColor);
+      //##### Border color #####
+      borderColorLabel = new JLabel( GeotoolsGUIUtil.RESOURCE.getString(RES_PREFIX+".BorderColor") );
+      borderColor = new ColorInputOption(null,true,Color.BLACK);
+      borderColor.addInputOptionListener(this);
+      SwingUtil.setPreferredWidth(borderColor, 40);
+      SwingUtil.fixComponentSize(borderColor);
+      //##### Border width #####
+      borderWidthLabel = new JLabel( GeotoolsGUIUtil.RESOURCE.getString(RES_PREFIX+".BorderWidth") );
+      borderWidth = new SelectionInputOption.Combo<Integer>(
+          null,
+          true,
+          new Integer[] {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20},
+          (Integer)2,
+          null
+      );
+      borderWidth.addInputOptionListener(this);
+      SwingUtil.setPreferredWidth(borderWidth, 50);
+      SwingUtil.fixComponentSize(borderWidth);
+      //##### Mark style #####
+      markLabel = new JLabel( GeotoolsGUIUtil.RESOURCE.getString(RES_PREFIX+".PointMark") );
+      markStyle = new SelectionInputOption.Combo<String>(
+          null,
+          true,
+          new String[] {
+              StyleBuilder.MARK_ARROW, 
+              StyleBuilder.MARK_CIRCLE, 
+              StyleBuilder.MARK_CROSS,
+              StyleBuilder.MARK_SQUARE,
+              StyleBuilder.MARK_STAR,
+              StyleBuilder.MARK_TRIANGLE,
+              StyleBuilder.MARK_X
+          },
+          StyleBuilder.MARK_CIRCLE,
+          new String[] {
+              GeotoolsGUIUtil.RESOURCE.getString("org.geotools.styling.StyleBuilder.MARK_ARROW"),
+              GeotoolsGUIUtil.RESOURCE.getString("org.geotools.styling.StyleBuilder.MARK_CIRCLE"),
+              GeotoolsGUIUtil.RESOURCE.getString("org.geotools.styling.StyleBuilder.MARK_CROSS"),
+              GeotoolsGUIUtil.RESOURCE.getString("org.geotools.styling.StyleBuilder.MARK_SQUARE"),
+              GeotoolsGUIUtil.RESOURCE.getString("org.geotools.styling.StyleBuilder.MARK_STAR"),
+              GeotoolsGUIUtil.RESOURCE.getString("org.geotools.styling.StyleBuilder.MARK_TRIANGLE"),
+              GeotoolsGUIUtil.RESOURCE.getString("org.geotools.styling.StyleBuilder.MARK_X")
+          }
+      );
+      markStyle.addInputOptionListener(this);
+      SwingUtil.fixComponentSize(markStyle);
+      markSize = new SelectionInputOption.Combo<Integer>(
+          null,
+          true,
+          new Integer[] {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20},
+          (Integer)5,
+          null
+      );
+      markSize.addInputOptionListener(this);
+      SwingUtil.setPreferredWidth(markSize, 50);
+      SwingUtil.fixComponentSize(markSize);
+
+      //##### put the components to the tool bar #####
+      add( fillColorLabel );
+      addSeparator( new Dimension(2,0) );
+      add( fillColor );
+      addSeparator( new Dimension(10,0) );
+      add( borderColorLabel );
+      addSeparator( new Dimension(2,0) );
+      add( borderColor );
+      addSeparator( new Dimension(10,0) );
+      add( borderWidthLabel );
+      addSeparator( new Dimension(2,0) );
+      add( borderWidth );
+      addSeparator( new Dimension(10,0) );
+      add( markLabel );
+      addSeparator( new Dimension(2,0) );
+      add( markStyle );
+      addSeparator( new Dimension(2,0) );
+      add( markSize );
+	}
+	
+	/**
+	 * Creates a point style with the currently set point style, size, fill and
+	 * border color.
+	 */
+	public Style createPointStyle() {
+	  return FeatureUtil.createPointStyle(
+	      (String)markStyle.getValue(),
+	      fillColor.getValue(),
+	      borderColor.getValue(),
+	      1.0,
+	      1.0,
+	      ((Number)markSize.getValue()).doubleValue(),
+	      0.0
+	  );
+	}
+
+    /**
+     * Creates a line style with the currently set border color and
+     * width.
+     */
+    public Style createLineStyle() {
+      return FeatureUtil.createLineStyle(
+          borderColor.getValue(),
+          ((Number)borderWidth.getValue()).doubleValue()
+      );
+    }
+
+    /**
+     * Creates a polygon style with the currently set fill, border color and
+     * width.
+     */
+    public Style createPolygonStyle() {
+      return FeatureUtil.createPolygonStyle(
+          fillColor.getValue(),
+          borderColor.getValue(),
+          ((Number)borderWidth.getValue()).doubleValue()
+      );
+    }
+
+    /**
+     * Called whenever one of the input options of this tool bar
+     * has changed its value. Invokes a {@link PropertyChangeEvent}
+     * according to the changed input option.
+     * @see #FILL_COLOR
+     * @see #BORDER_COLOR
+     * @see #BORDER_WIDTH
+     * @see #MARK_STYLE
+     * @see #MARK_SIZE
+     */
+    public void optionChanged(InputOption option, Object oldValue, Object newValue) {
+      String changedProperty = null;
+      if ( option == fillColor )
+        changedProperty = FILL_COLOR;
+      if ( option == borderColor )
+        changedProperty = BORDER_COLOR;
+      if ( option == borderWidth )
+        changedProperty = BORDER_WIDTH;
+      if ( option == markStyle )
+        changedProperty = MARK_STYLE;
+      if ( option == markSize )
+        changedProperty = MARK_SIZE;
+      
+      if ( changedProperty != null )
+        firePropertyChange(changedProperty, oldValue, newValue);
+    }
+
+    /**
+     * Called whenever one of the input options of this tool bar
+     * lost focus. Does nothing.
+     */
+    public void optionLostFocus(InputOption option) {
+    }
+
+    /**
+     * Called whenever one of the input options of this tool bar
+     * gained focus. Does nothing.
+     */
+    public void optionGainedFocus(InputOption option) {}
+
+}

Modified: trunk/src/schmitzm/geotools/gui/resource/locales/GTResourceBundle.properties
===================================================================
--- trunk/src/schmitzm/geotools/gui/resource/locales/GTResourceBundle.properties	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/resource/locales/GTResourceBundle.properties	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,118 +1,147 @@
-# ---------------------------------------------------------------
-# ------ Default Translations (english) for GUI components ------
-# ------ in Package schmitz.geotools.gui                   ------
-# ---------------------------------------------------------------
-
-Attributes=Attributes
-
-org.geotools.styling.StyleBuilder.MARK_ARROW=Arrow
-org.geotools.styling.StyleBuilder.MARK_CIRCLE=Circle
-org.geotools.styling.StyleBuilder.MARK_CROSS=Cross
-org.geotools.styling.StyleBuilder.MARK_SQUARE=Square
-org.geotools.styling.StyleBuilder.MARK_STAR=Star
-org.geotools.styling.StyleBuilder.MARK_TRIANGLE=Triangle
-org.geotools.styling.StyleBuilder.MARK_X=X
-
-schmitzm.geotools.feature.FeatureTableModel.AttrName=Attribut
-schmitzm.geotools.feature.FeatureTableModel.AttrType=Type
-schmitzm.geotools.feature.FeatureTableModel.AttrValue=Value
-
-schmitzm.geotools.gui.FeatureCollectionFilterPanel.TestButton=Test filter
-schmitzm.geotools.gui.FeatureCollectionFilterPanel.TestResultDetailsButton=?
-schmitzm.geotools.gui.FeatureCollectionFilterPanel.TestResultDetailsToolTip=Show error details...
-schmitzm.geotools.gui.FeatureCollectionFilterPanel.ResultsBorderTitle=Filter result:
-schmitzm.geotools.gui.FeatureCollectionFilterPanel.FilterDefinitionBorderTitle=Define filter:
-schmitzm.geotools.gui.FeatureCollectionFilterPanel.PreviewMapPaneToolTip=Red features are included by the filter,\ngray features are not.
-
-schmitzm.geotools.gui.FeatureTablePane.PreviewMapPaneToolTip=Red features are selected,\ngray features are not.
-
-schmitzm.geotools.gui.FeatureLayerFilterDialog.TITLE = Feature-Filter
-
-schmitzm.geotools.gui.MapActionControlPane.INFO=Info
-schmitzm.geotools.gui.MapActionControlPane.ZOOM_IN=Zoom in
-schmitzm.geotools.gui.MapActionControlPane.ZOOM_OUT=Zoom out
-schmitzm.geotools.gui.MapActionControlPane.SELECT_TOP=Select from top layer
-schmitzm.geotools.gui.MapActionControlPane.SELECT_ALL=Select from all layers
-schmitzm.geotools.gui.MapContextControlPane.Menu.MOVE_UP=Move layer UP
-schmitzm.geotools.gui.MapContextControlPane.Menu.MOVE_DOWN=Move layer DOWN
-schmitzm.geotools.gui.MapContextControlPane.Menu.ZOOM_TO=Zoom to layer
-schmitzm.geotools.gui.MapContextControlPane.Menu.FILTER=Filter layer...
-schmitzm.geotools.gui.MapContextControlPane.Menu.RECOLOR=Recolor layer
-schmitzm.geotools.gui.MapContextControlPane.Menu.REMOVE=Remove layer
-schmitzm.geotools.gui.MapContextControlPane.Menu.SHOWALL=Show all layers
-schmitzm.geotools.gui.MapContextControlPane.Menu.HIDEALL=Hide all layers
-schmitzm.geotools.gui.MapContextControlPane.Menu.INVERTALL=Invert all layers
-schmitzm.geotools.gui.MapContextControlPane.Menu.CUSTOMIZE=Customize...
-schmitzm.geotools.gui.MapContextControlPane.ColorMapDialog.TITLE=Color map
-schmitzm.geotools.gui.MapContextControlPane.SaveColorMapDialog.TITLE=New color map
-schmitzm.geotools.gui.MapContextControlPane.SaveColorMapDialog.QUESTION=Enter a name for the new color map...
-schmitzm.geotools.gui.ColorMapTable.Header.QUANTITY=Quantity
-schmitzm.geotools.gui.ColorMapTable.Header.COLOR=Color
-schmitzm.geotools.gui.ColorMapTable.Header.LABEL=Label
-schmitzm.geotools.gui.RasterPositionLabel.LABEL_PREFIX=Raster value
-schmitzm.geotools.gui.GeotoolsGUIUtil.Load=Load
-schmitzm.geotools.gui.GeotoolsGUIUtil.LoadRaster=Load raster
-schmitzm.geotools.gui.GeotoolsGUIUtil.LoadFeature=Load vector
-schmitzm.geotools.gui.GeotoolsGUIUtil.Save=Save
-schmitzm.geotools.gui.GeotoolsGUIUtil.SaveRaster=Save raster
-schmitzm.geotools.gui.GeotoolsGUIUtil.SaveFeature=Save vector
-schmitzm.geotools.gui.GeotoolsGUIUtil.NORTH=North
-schmitzm.geotools.gui.GeotoolsGUIUtil.SOUTH=South
-schmitzm.geotools.gui.GeotoolsGUIUtil.WEST=West
-schmitzm.geotools.gui.GeotoolsGUIUtil.EAST=East
-schmitzm.geotools.gui.GeotoolsGUIUtil.North=Nord
-schmitzm.geotools.gui.GeotoolsGUIUtil.South=South
-schmitzm.geotools.gui.GeotoolsGUIUtil.West=West
-schmitzm.geotools.gui.GeotoolsGUIUtil.East=East
-schmitzm.geotools.gui.GeotoolsGUIUtil.NORTH.Abb=N
-schmitzm.geotools.gui.GeotoolsGUIUtil.SOUTH.Abb=S
-schmitzm.geotools.gui.GeotoolsGUIUtil.WEST.Abb=W
-schmitzm.geotools.gui.GeotoolsGUIUtil.EAST.Abb=E
-schmitzm.geotools.gui.CRSSelectionDialog.init.crs.title=CRS database
-schmitzm.geotools.gui.CRSSelectionDialog.init.crs.mess=Initialize CRS database. Please wait...
-schmitzm.geotools.gui.CRSSelectionDialog.title=Choose a coordinate reference system (CRS)
-schmitzm.geotools.gui.CRSSelectionDialog.mandatory=CRS must be specified!
-schmitzm.geotools.gui.CRSSelectionDialog.button.wgs84=WGS-84 CRS
-schmitzm.geotools.gui.CRSSelectionDialog.button.default=Default CRS (${0})
-schmitzm.geotools.gui.CRSSelectionDialog.button.predefined=Predefined
-schmitzm.geotools.gui.CRSSelectionDialog.button.userDefined=User defined:
-schmitzm.geotools.gui.JEditorPane.Err.MissingMap=First a layer must be displayed (to define CRS and geo-position).
-schmitzm.geotools.gui.JEditorPane.Err.Line.LessPoints=For a line feature at least 2 points must be specified!
-schmitzm.geotools.gui.JEditorPane.Err.Polygon.LessPoints=For a polygon feature at least 3 points must be specified!
-schmitzm.geotools.gui.JEditorToolBar.button.layer.new=Create new layer
-schmitzm.geotools.gui.JEditorToolBar.button.layer.save=Finish layer
-schmitzm.geotools.gui.JEditorToolBar.button.layer.cancel=Abort layer
-schmitzm.geotools.gui.JEditorToolBar.button.edit.undo=Undo last editing operation
-schmitzm.geotools.gui.JEditorToolBar.button.edit.redo=Redo last undone editing operation
-schmitzm.geotools.gui.JEditorToolBar.button.edit.clear=Undo all editing operation
-schmitzm.geotools.gui.JEditorToolBar.button.edit.finish=Start new feature
-schmitzm.geotools.gui.JEditorToolBar.NewLayer.dialog.title=Create new layer...
-schmitzm.geotools.gui.JEditorToolBar.NewLayer.layer.title=Layer title
-schmitzm.geotools.gui.JEditorToolBar.NewLayer.layer.title.default=New Layer
-schmitzm.geotools.gui.JEditorToolBar.NewLayer.layer.type=Layer type
-schmitzm.geotools.gui.JEditorToolBar.NewLayer.layer.type.point=Point layer
-schmitzm.geotools.gui.JEditorToolBar.NewLayer.layer.type.line=Line layer
-schmitzm.geotools.gui.JEditorToolBar.NewLayer.layer.type.polygon=Polygon layer
-schmitzm.geotools.gui.JEditorToolBar.NewLayer.ftype.title=Non-Geometric attributes
-schmitzm.geotools.gui.JEditorToolBar.NewLayer.Err.GeomAttr=Attribute name '${0}' reserverd for default geometry.
-schmitzm.geotools.gui.JEditorToolBar.NewLayer.Err.AutoVal=Auto value not supported for attribut type '${0}'.
-schmitzm.geotools.gui.JEditorToolBar.NewFeature.title=New feature attributes
-schmitzm.geotools.gui.StyleToolBar.FillColor=Fill
-schmitzm.geotools.gui.StyleToolBar.BorderColor=Border
-schmitzm.geotools.gui.StyleToolBar.BorderWidth=Border width
-schmitzm.geotools.gui.StyleToolBar.PointMark=Point style
-schmitzm.geotools.gui.FeatureTypeBuilderTableModel.AttrName=Name
-schmitzm.geotools.gui.FeatureTypeBuilderTableModel.AttrType=Type
-schmitzm.geotools.gui.FeatureTypeBuilderTableModel.Nillable=Nillable
-schmitzm.geotools.gui.FeatureTypeBuilderTableModel.AutoValue=Auto
-schmitzm.geotools.gui.FeatureTypeBuilderTableModel.DefValue=Default
-schmitzm.geotools.gui.FeatureTypeBuilderTableModel.NewAttr=Attribute_${0}
-
-schmitzm.geotools.gui.SelectableFeatureTablePane.button.clearSelection.tt=Clear selection
-schmitzm.geotools.gui.SelectableFeatureTablePane.button.selectionToTop.tt=Move selected to the top of the table
-schmitzm.geotools.gui.SelectableFeatureTablePane.button.invertSelection.tt=Invert selection
-schmitzm.geotools.gui.SelectableFeatureTablePane.button.zoomToSelection.tt=Zoom to selected features
-schmitzm.geotools.gui.SelectableFeatureTablePane.selectionStatus=${0} of ${1} ${2} selected.
-schmitzm.geotools.gui.SelectableFeatureTablePane.selectionStatus.polygons=polygons
-schmitzm.geotools.gui.SelectableFeatureTablePane.selectionStatus.points=points
-schmitzm.geotools.gui.SelectableFeatureTablePane.selectionStatus.lines=lines
\ No newline at end of file
+##########
+#Copyright (c) 2009 Martin O. J. Schmitz.
+#
+#This file is part of the SCHMITZM library - a collection of utility 
+#classes based on Java 1.6, focussing (not only) on Java Swing 
+#and the Geotools library.
+#
+#The SCHMITZM project is hosted at:
+#http://wald.intevation.org/projects/schmitzm/
+#
+#This program is free software; you can redistribute it and/or
+#modify it under the terms of the GNU Lesser General Public License
+#as published by the Free Software Foundation; either version 3
+#of the License, or (at your option) any later version.
+#
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+#
+#You should have received a copy of the GNU Lesser General Public License (license.txt)
+#along with this program; if not, write to the Free Software
+#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#or try this link: http://www.gnu.org/licenses/lgpl.html
+#
+#Contributors:
+#    Martin O. J. Schmitz - initial API and implementation
+#    Stefan A. Krüger - additional utility classes
+##########
+# ---------------------------------------------------------------
+# ------ Default Translations (english) for GUI components ------
+# ------ in Package schmitz.geotools.gui                   ------
+# ---------------------------------------------------------------
+
+Attributes=Attributes
+
+org.geotools.styling.StyleBuilder.MARK_ARROW=Arrow
+org.geotools.styling.StyleBuilder.MARK_CIRCLE=Circle
+org.geotools.styling.StyleBuilder.MARK_CROSS=Cross
+org.geotools.styling.StyleBuilder.MARK_SQUARE=Square
+org.geotools.styling.StyleBuilder.MARK_STAR=Star
+org.geotools.styling.StyleBuilder.MARK_TRIANGLE=Triangle
+org.geotools.styling.StyleBuilder.MARK_X=X
+
+schmitzm.geotools.feature.FeatureTableModel.AttrName=Attribut
+schmitzm.geotools.feature.FeatureTableModel.AttrType=Type
+schmitzm.geotools.feature.FeatureTableModel.AttrValue=Value
+
+schmitzm.geotools.gui.FeatureCollectionFilterPanel.TestButton=Test filter
+schmitzm.geotools.gui.FeatureCollectionFilterPanel.TestResultDetailsButton=?
+schmitzm.geotools.gui.FeatureCollectionFilterPanel.TestResultDetailsToolTip=Show error details...
+schmitzm.geotools.gui.FeatureCollectionFilterPanel.ResultsBorderTitle=Filter result:
+schmitzm.geotools.gui.FeatureCollectionFilterPanel.FilterDefinitionBorderTitle=Define filter:
+schmitzm.geotools.gui.FeatureCollectionFilterPanel.PreviewMapPaneToolTip=Red features are included by the filter,\ngray features are not.
+
+schmitzm.geotools.gui.FeatureTablePane.PreviewMapPaneToolTip=Red features are selected,\ngray features are not.
+
+schmitzm.geotools.gui.FeatureLayerFilterDialog.TITLE = Feature-Filter
+
+schmitzm.geotools.gui.MapActionControlPane.INFO=Info
+schmitzm.geotools.gui.MapActionControlPane.ZOOM_IN=Zoom in
+schmitzm.geotools.gui.MapActionControlPane.ZOOM_OUT=Zoom out
+schmitzm.geotools.gui.MapActionControlPane.SELECT_TOP=Select from top layer
+schmitzm.geotools.gui.MapActionControlPane.SELECT_ALL=Select from all layers
+schmitzm.geotools.gui.MapContextControlPane.Menu.MOVE_UP=Move layer UP
+schmitzm.geotools.gui.MapContextControlPane.Menu.MOVE_DOWN=Move layer DOWN
+schmitzm.geotools.gui.MapContextControlPane.Menu.ZOOM_TO=Zoom to layer
+schmitzm.geotools.gui.MapContextControlPane.Menu.FILTER=Filter layer...
+schmitzm.geotools.gui.MapContextControlPane.Menu.RECOLOR=Recolor layer
+schmitzm.geotools.gui.MapContextControlPane.Menu.REMOVE=Remove layer
+schmitzm.geotools.gui.MapContextControlPane.Menu.SHOWALL=Show all layers
+schmitzm.geotools.gui.MapContextControlPane.Menu.HIDEALL=Hide all layers
+schmitzm.geotools.gui.MapContextControlPane.Menu.INVERTALL=Invert all layers
+schmitzm.geotools.gui.MapContextControlPane.Menu.CUSTOMIZE=Customize...
+schmitzm.geotools.gui.MapContextControlPane.ColorMapDialog.TITLE=Color map
+schmitzm.geotools.gui.MapContextControlPane.SaveColorMapDialog.TITLE=New color map
+schmitzm.geotools.gui.MapContextControlPane.SaveColorMapDialog.QUESTION=Enter a name for the new color map...
+schmitzm.geotools.gui.ColorMapTable.Header.QUANTITY=Quantity
+schmitzm.geotools.gui.ColorMapTable.Header.COLOR=Color
+schmitzm.geotools.gui.ColorMapTable.Header.LABEL=Label
+schmitzm.geotools.gui.RasterPositionLabel.LABEL_PREFIX=Raster value
+schmitzm.geotools.gui.GeotoolsGUIUtil.Load=Load
+schmitzm.geotools.gui.GeotoolsGUIUtil.LoadRaster=Load raster
+schmitzm.geotools.gui.GeotoolsGUIUtil.LoadFeature=Load vector
+schmitzm.geotools.gui.GeotoolsGUIUtil.Save=Save
+schmitzm.geotools.gui.GeotoolsGUIUtil.SaveRaster=Save raster
+schmitzm.geotools.gui.GeotoolsGUIUtil.SaveFeature=Save vector
+schmitzm.geotools.gui.GeotoolsGUIUtil.NORTH=North
+schmitzm.geotools.gui.GeotoolsGUIUtil.SOUTH=South
+schmitzm.geotools.gui.GeotoolsGUIUtil.WEST=West
+schmitzm.geotools.gui.GeotoolsGUIUtil.EAST=East
+schmitzm.geotools.gui.GeotoolsGUIUtil.North=Nord
+schmitzm.geotools.gui.GeotoolsGUIUtil.South=South
+schmitzm.geotools.gui.GeotoolsGUIUtil.West=West
+schmitzm.geotools.gui.GeotoolsGUIUtil.East=East
+schmitzm.geotools.gui.GeotoolsGUIUtil.NORTH.Abb=N
+schmitzm.geotools.gui.GeotoolsGUIUtil.SOUTH.Abb=S
+schmitzm.geotools.gui.GeotoolsGUIUtil.WEST.Abb=W
+schmitzm.geotools.gui.GeotoolsGUIUtil.EAST.Abb=E
+schmitzm.geotools.gui.CRSSelectionDialog.init.crs.title=CRS database
+schmitzm.geotools.gui.CRSSelectionDialog.init.crs.mess=Initialize CRS database. Please wait...
+schmitzm.geotools.gui.CRSSelectionDialog.title=Choose a coordinate reference system (CRS)
+schmitzm.geotools.gui.CRSSelectionDialog.mandatory=CRS must be specified!
+schmitzm.geotools.gui.CRSSelectionDialog.button.wgs84=WGS-84 CRS
+schmitzm.geotools.gui.CRSSelectionDialog.button.default=Default CRS (${0})
+schmitzm.geotools.gui.CRSSelectionDialog.button.predefined=Predefined
+schmitzm.geotools.gui.CRSSelectionDialog.button.userDefined=User defined:
+schmitzm.geotools.gui.JEditorPane.Err.MissingMap=First a layer must be displayed (to define CRS and geo-position).
+schmitzm.geotools.gui.JEditorPane.Err.Line.LessPoints=For a line feature at least 2 points must be specified!
+schmitzm.geotools.gui.JEditorPane.Err.Polygon.LessPoints=For a polygon feature at least 3 points must be specified!
+schmitzm.geotools.gui.JEditorToolBar.button.layer.new=Create new layer
+schmitzm.geotools.gui.JEditorToolBar.button.layer.save=Finish layer
+schmitzm.geotools.gui.JEditorToolBar.button.layer.cancel=Abort layer
+schmitzm.geotools.gui.JEditorToolBar.button.edit.undo=Undo last editing operation
+schmitzm.geotools.gui.JEditorToolBar.button.edit.redo=Redo last undone editing operation
+schmitzm.geotools.gui.JEditorToolBar.button.edit.clear=Undo all editing operation
+schmitzm.geotools.gui.JEditorToolBar.button.edit.finish=Start new feature
+schmitzm.geotools.gui.JEditorToolBar.NewLayer.dialog.title=Create new layer...
+schmitzm.geotools.gui.JEditorToolBar.NewLayer.layer.title=Layer title
+schmitzm.geotools.gui.JEditorToolBar.NewLayer.layer.title.default=New Layer
+schmitzm.geotools.gui.JEditorToolBar.NewLayer.layer.type=Layer type
+schmitzm.geotools.gui.JEditorToolBar.NewLayer.layer.type.point=Point layer
+schmitzm.geotools.gui.JEditorToolBar.NewLayer.layer.type.line=Line layer
+schmitzm.geotools.gui.JEditorToolBar.NewLayer.layer.type.polygon=Polygon layer
+schmitzm.geotools.gui.JEditorToolBar.NewLayer.ftype.title=Non-Geometric attributes
+schmitzm.geotools.gui.JEditorToolBar.NewLayer.Err.GeomAttr=Attribute name '${0}' reserverd for default geometry.
+schmitzm.geotools.gui.JEditorToolBar.NewLayer.Err.AutoVal=Auto value not supported for attribut type '${0}'.
+schmitzm.geotools.gui.JEditorToolBar.NewFeature.title=New feature attributes
+schmitzm.geotools.gui.StyleToolBar.FillColor=Fill
+schmitzm.geotools.gui.StyleToolBar.BorderColor=Border
+schmitzm.geotools.gui.StyleToolBar.BorderWidth=Border width
+schmitzm.geotools.gui.StyleToolBar.PointMark=Point style
+schmitzm.geotools.gui.FeatureTypeBuilderTableModel.AttrName=Name
+schmitzm.geotools.gui.FeatureTypeBuilderTableModel.AttrType=Type
+schmitzm.geotools.gui.FeatureTypeBuilderTableModel.Nillable=Nillable
+schmitzm.geotools.gui.FeatureTypeBuilderTableModel.AutoValue=Auto
+schmitzm.geotools.gui.FeatureTypeBuilderTableModel.DefValue=Default
+schmitzm.geotools.gui.FeatureTypeBuilderTableModel.NewAttr=Attribute_${0}
+
+schmitzm.geotools.gui.SelectableFeatureTablePane.button.clearSelection.tt=Clear selection
+schmitzm.geotools.gui.SelectableFeatureTablePane.button.selectionToTop.tt=Move selected to the top of the table
+schmitzm.geotools.gui.SelectableFeatureTablePane.button.invertSelection.tt=Invert selection
+schmitzm.geotools.gui.SelectableFeatureTablePane.button.zoomToSelection.tt=Zoom to selected features
+schmitzm.geotools.gui.SelectableFeatureTablePane.selectionStatus=${0} of ${1} ${2} selected.
+schmitzm.geotools.gui.SelectableFeatureTablePane.selectionStatus.polygons=polygons
+schmitzm.geotools.gui.SelectableFeatureTablePane.selectionStatus.points=points
+schmitzm.geotools.gui.SelectableFeatureTablePane.selectionStatus.lines=lines

Modified: trunk/src/schmitzm/geotools/gui/resource/locales/GTResourceBundle_de.properties
===================================================================
--- trunk/src/schmitzm/geotools/gui/resource/locales/GTResourceBundle_de.properties	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/resource/locales/GTResourceBundle_de.properties	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,113 +1,142 @@
-# ----------------------------------------------------
-# ------ German Translations for GUI components ------
-# ------ in Package schmitz.geotools.gui        ------
-# ----------------------------------------------------
-
-Attributes=Attribute
-
-org.geotools.styling.StyleBuilder.MARK_ARROW=Pfeil
-org.geotools.styling.StyleBuilder.MARK_CIRCLE=Kreis
-org.geotools.styling.StyleBuilder.MARK_CROSS=Kreuz
-org.geotools.styling.StyleBuilder.MARK_SQUARE=Quadrat
-org.geotools.styling.StyleBuilder.MARK_STAR=Stern
-org.geotools.styling.StyleBuilder.MARK_TRIANGLE=Dreieck
-org.geotools.styling.StyleBuilder.MARK_X=X
-
-schmitzm.geotools.gui.FeatureCollectionFilterPanel.TestButton=Filter testen
-schmitzm.geotools.gui.FeatureCollectionFilterPanel.TestResultDetailsButton=?
-schmitzm.geotools.gui.FeatureCollectionFilterPanel.TestResultDetailsToolTip=Fehler-Details anzeigen...
-schmitzm.geotools.gui.FeatureCollectionFilterPanel.ResultsBorderTitle=Ergebnis des Filters:
-schmitzm.geotools.gui.FeatureCollectionFilterPanel.FilterDefinitionBorderTitle=Filter definieren:
-schmitzm.geotools.gui.FeatureCollectionFilterPanel.PreviewMapPaneToolTip=Rote Objekte treffen auf den Filter zu, graue Objekte nicht.
-
-schmitzm.geotools.gui.FeatureTablePane.PreviewMapPaneToolTip=Rote Objekte sind selektiert, graue Objekte nicht.
-
-schmitzm.geotools.gui.FeatureLayerFilterDialog.TITLE = Feature-Filter
-
-schmitzm.geotools.gui.MapActionControlPane.ZOOM_IN=Heran zoomen
-schmitzm.geotools.gui.MapActionControlPane.ZOOM_OUT=Heraus zoomen
-schmitzm.geotools.gui.MapActionControlPane.SELECT_TOP=Auswählen aus oberstem Layer
-schmitzm.geotools.gui.MapActionControlPane.SELECT_ALL=Auswählen aus allen Layern
-schmitzm.geotools.gui.MapContextControlPane.Menu.MOVE_UP=Nach OBEN schieben
-schmitzm.geotools.gui.MapContextControlPane.Menu.MOVE_DOWN=Nach UNTEN schieben
-schmitzm.geotools.gui.MapContextControlPane.Menu.ZOOM_TO=Zu Layer zoomen
-schmitzm.geotools.gui.MapContextControlPane.Menu.FILTER=Layer filtern...
-schmitzm.geotools.gui.MapContextControlPane.Menu.RECOLOR=Färbung ändern
-schmitzm.geotools.gui.MapContextControlPane.Menu.REMOVE=Layer entfernen
-schmitzm.geotools.gui.MapContextControlPane.Menu.SHOWALL=Alle Layer anzeigen
-schmitzm.geotools.gui.MapContextControlPane.Menu.HIDEALL=Alle Layer verbergen
-schmitzm.geotools.gui.MapContextControlPane.Menu.INVERTALL=Alle Layer invertieren
-schmitzm.geotools.gui.MapContextControlPane.Menu.CUSTOMIZE=Anpassen...
-schmitzm.geotools.gui.MapContextControlPane.ColorMapDialog.TITLE=Farbpalette
-schmitzm.geotools.gui.MapContextControlPane.SaveColorMapDialog.TITLE=Farbpalette speichern
-schmitzm.geotools.gui.MapContextControlPane.SaveColorMapDialog.QUESTION=Name für neue Farbpalette...
-schmitzm.geotools.gui.ColorMapTable.Header.QUANTITY=Raster-Wert
-schmitzm.geotools.gui.ColorMapTable.Header.COLOR=Farbe
-schmitzm.geotools.gui.ColorMapTable.Header.LABEL=Label
-schmitzm.geotools.gui.RasterPositionLabel.LABEL_PREFIX=Raster-Wert
-schmitzm.geotools.gui.GeotoolsGUIUtil.Load=Laden
-schmitzm.geotools.gui.GeotoolsGUIUtil.LoadRaster=Raster laden
-schmitzm.geotools.gui.GeotoolsGUIUtil.LoadFeature=Shape laden
-schmitzm.geotools.gui.GeotoolsGUIUtil.Save=Speichern
-schmitzm.geotools.gui.GeotoolsGUIUtil.SaveRaster=Raster speichern
-schmitzm.geotools.gui.GeotoolsGUIUtil.SaveFeature=Shape speichern
-schmitzm.geotools.gui.GeotoolsGUIUtil.NORTH=Nord
-schmitzm.geotools.gui.GeotoolsGUIUtil.SOUTH=Süd
-schmitzm.geotools.gui.GeotoolsGUIUtil.WEST=West
-schmitzm.geotools.gui.GeotoolsGUIUtil.EAST=Ost
-schmitzm.geotools.gui.GeotoolsGUIUtil.North=Norden
-schmitzm.geotools.gui.GeotoolsGUIUtil.South=Süden
-schmitzm.geotools.gui.GeotoolsGUIUtil.West=Westen
-schmitzm.geotools.gui.GeotoolsGUIUtil.East=Osten
-schmitzm.geotools.gui.GeotoolsGUIUtil.NORTH.Abb=N
-schmitzm.geotools.gui.GeotoolsGUIUtil.SOUTH.Abb=S
-schmitzm.geotools.gui.GeotoolsGUIUtil.WEST.Abb=W
-schmitzm.geotools.gui.GeotoolsGUIUtil.EAST.Abb=O
-schmitzm.geotools.gui.CRSSelectionDialog.init.crs.title=CRS datenbank
-schmitzm.geotools.gui.CRSSelectionDialog.init.crs.mess=CRS-Datenbank wird initialisiert. Bitte warten...
-schmitzm.geotools.gui.CRSSelectionDialog.title=Koordinaten-System (CRS) auswählen
-schmitzm.geotools.gui.CRSSelectionDialog.mandatory=CRS must be specified!
-schmitzm.geotools.gui.CRSSelectionDialog.button.wgs84=WGS-84 CRS
-schmitzm.geotools.gui.CRSSelectionDialog.button.default=Standard CRS (${0})
-schmitzm.geotools.gui.CRSSelectionDialog.button.predefined=Vordefiniert
-schmitzm.geotools.gui.CRSSelectionDialog.button.userDefined=Benutzerdefiniert:
-schmitzm.geotools.gui.JEditorPane.Err.MissingMap=Bevor ein neues Layer erstellt werden kann, muss ein Layer angezeigt werden (um CRS und geogr. Lage zu definieren).
-schmitzm.geotools.gui.JEditorPane.Err.Line.LessPoints=Für ein Line-Feature müssen mind. 2 Punkte definiert werden!
-schmitzm.geotools.gui.JEditorPane.Err.Polygon.LessPoints=Für ein Polygon-Feature müssen mind. 3 Punkte definiert werden!
-schmitzm.geotools.gui.JEditorToolBar.button.layer.new=Neues Layer erstellen
-schmitzm.geotools.gui.JEditorToolBar.button.layer.save=Layer abschliessen
-schmitzm.geotools.gui.JEditorToolBar.button.layer.cancel=Layer abbrechen
-schmitzm.geotools.gui.JEditorToolBar.button.edit.undo=Letzte Operation zurücknehmen
-schmitzm.geotools.gui.JEditorToolBar.button.edit.redo=Letzte zurückgenommene Operation wiederholen
-schmitzm.geotools.gui.JEditorToolBar.button.edit.clear=Layer leeren
-schmitzm.geotools.gui.JEditorToolBar.button.edit.finish=Neues Feature starten
-schmitzm.geotools.gui.JEditorToolBar.NewLayer.dialog.title=Neues Layer erzeugen
-schmitzm.geotools.gui.JEditorToolBar.NewLayer.layer.title=Layer-Bezeichnung
-schmitzm.geotools.gui.JEditorToolBar.NewLayer.layer.title.default=Neues Layer
-schmitzm.geotools.gui.JEditorToolBar.NewLayer.layer.type=Layer-Art
-schmitzm.geotools.gui.JEditorToolBar.NewLayer.layer.type.point=Punkt-Layer
-schmitzm.geotools.gui.JEditorToolBar.NewLayer.layer.type.line=Linien-Layer
-schmitzm.geotools.gui.JEditorToolBar.NewLayer.layer.type.polygon=Polygon-Layer
-schmitzm.geotools.gui.JEditorToolBar.NewLayer.ftype.title=Weitere Attribute
-schmitzm.geotools.gui.JEditorToolBar.NewLayer.Err.GeomAttr=Attribut-Name '${0}' reserviert für das Default-Geometrie-Attribut.
-schmitzm.geotools.gui.JEditorToolBar.NewLayer.Err.AutoVal=Auto-Wert für Attribut-Typ '${0}' nicht möglich.
-schmitzm.geotools.gui.JEditorToolBar.NewFeature.title=Neues Feature
-schmitzm.geotools.gui.StyleToolBar.FillColor=Füllfarbe
-schmitzm.geotools.gui.StyleToolBar.BorderColor=Randfarbe
-schmitzm.geotools.gui.StyleToolBar.BorderWidth=Randbreite
-schmitzm.geotools.gui.StyleToolBar.PointMark=Punkt-Style
-schmitzm.geotools.gui.FeatureTypeBuilderTableModel.AttrName=Name
-schmitzm.geotools.gui.FeatureTypeBuilderTableModel.AttrType=Typ
-schmitzm.geotools.gui.FeatureTypeBuilderTableModel.Nillable=Nullable
-schmitzm.geotools.gui.FeatureTypeBuilderTableModel.AutoValue=Auto-Wert
-schmitzm.geotools.gui.FeatureTypeBuilderTableModel.DefValue=Default
-schmitzm.geotools.gui.FeatureTypeBuilderTableModel.NewAttr=Attribut_${0}
-
-schmitzm.geotools.gui.SelectableFeatureTablePane.button.clearSelection.tt=Auswahl aufheben
-schmitzm.geotools.gui.SelectableFeatureTablePane.button.selectionToTop.tt=Ausgewählte Zeilen in der Tabelle nach oben verschieben 
-schmitzm.geotools.gui.SelectableFeatureTablePane.button.invertSelection.tt=Auswahl umkehren
-schmitzm.geotools.gui.SelectableFeatureTablePane.button.zoomToSelection.tt=Zoomt zu den ausgewählten Geoobjekten 
-schmitzm.geotools.gui.SelectableFeatureTablePane.selectionStatus=${0} von ${1} ${2} selektiert.
-schmitzm.geotools.gui.SelectableFeatureTablePane.selectionStatus.polygons=Polygonen
-schmitzm.geotools.gui.SelectableFeatureTablePane.selectionStatus.points=Punkten
-schmitzm.geotools.gui.SelectableFeatureTablePane.selectionStatus.lines=Linien
\ No newline at end of file
+##########
+#Copyright (c) 2009 Martin O. J. Schmitz.
+#
+#This file is part of the SCHMITZM library - a collection of utility 
+#classes based on Java 1.6, focussing (not only) on Java Swing 
+#and the Geotools library.
+#
+#The SCHMITZM project is hosted at:
+#http://wald.intevation.org/projects/schmitzm/
+#
+#This program is free software; you can redistribute it and/or
+#modify it under the terms of the GNU Lesser General Public License
+#as published by the Free Software Foundation; either version 3
+#of the License, or (at your option) any later version.
+#
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+#
+#You should have received a copy of the GNU Lesser General Public License (license.txt)
+#along with this program; if not, write to the Free Software
+#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#or try this link: http://www.gnu.org/licenses/lgpl.html
+#
+#Contributors:
+#    Martin O. J. Schmitz - initial API and implementation
+#    Stefan A. Krüger - additional utility classes
+##########
+# ----------------------------------------------------
+# ------ German Translations for GUI components ------
+# ------ in Package schmitz.geotools.gui        ------
+# ----------------------------------------------------
+
+Attributes=Attribute
+
+org.geotools.styling.StyleBuilder.MARK_ARROW=Pfeil
+org.geotools.styling.StyleBuilder.MARK_CIRCLE=Kreis
+org.geotools.styling.StyleBuilder.MARK_CROSS=Kreuz
+org.geotools.styling.StyleBuilder.MARK_SQUARE=Quadrat
+org.geotools.styling.StyleBuilder.MARK_STAR=Stern
+org.geotools.styling.StyleBuilder.MARK_TRIANGLE=Dreieck
+org.geotools.styling.StyleBuilder.MARK_X=X
+
+schmitzm.geotools.gui.FeatureCollectionFilterPanel.TestButton=Filter testen
+schmitzm.geotools.gui.FeatureCollectionFilterPanel.TestResultDetailsButton=?
+schmitzm.geotools.gui.FeatureCollectionFilterPanel.TestResultDetailsToolTip=Fehler-Details anzeigen...
+schmitzm.geotools.gui.FeatureCollectionFilterPanel.ResultsBorderTitle=Ergebnis des Filters:
+schmitzm.geotools.gui.FeatureCollectionFilterPanel.FilterDefinitionBorderTitle=Filter definieren:
+schmitzm.geotools.gui.FeatureCollectionFilterPanel.PreviewMapPaneToolTip=Rote Objekte treffen auf den Filter zu, graue Objekte nicht.
+
+schmitzm.geotools.gui.FeatureTablePane.PreviewMapPaneToolTip=Rote Objekte sind selektiert, graue Objekte nicht.
+
+schmitzm.geotools.gui.FeatureLayerFilterDialog.TITLE = Feature-Filter
+
+schmitzm.geotools.gui.MapActionControlPane.ZOOM_IN=Heran zoomen
+schmitzm.geotools.gui.MapActionControlPane.ZOOM_OUT=Heraus zoomen
+schmitzm.geotools.gui.MapActionControlPane.SELECT_TOP=Auswählen aus oberstem Layer
+schmitzm.geotools.gui.MapActionControlPane.SELECT_ALL=Auswählen aus allen Layern
+schmitzm.geotools.gui.MapContextControlPane.Menu.MOVE_UP=Nach OBEN schieben
+schmitzm.geotools.gui.MapContextControlPane.Menu.MOVE_DOWN=Nach UNTEN schieben
+schmitzm.geotools.gui.MapContextControlPane.Menu.ZOOM_TO=Zu Layer zoomen
+schmitzm.geotools.gui.MapContextControlPane.Menu.FILTER=Layer filtern...
+schmitzm.geotools.gui.MapContextControlPane.Menu.RECOLOR=Färbung ändern
+schmitzm.geotools.gui.MapContextControlPane.Menu.REMOVE=Layer entfernen
+schmitzm.geotools.gui.MapContextControlPane.Menu.SHOWALL=Alle Layer anzeigen
+schmitzm.geotools.gui.MapContextControlPane.Menu.HIDEALL=Alle Layer verbergen
+schmitzm.geotools.gui.MapContextControlPane.Menu.INVERTALL=Alle Layer invertieren
+schmitzm.geotools.gui.MapContextControlPane.Menu.CUSTOMIZE=Anpassen...
+schmitzm.geotools.gui.MapContextControlPane.ColorMapDialog.TITLE=Farbpalette
+schmitzm.geotools.gui.MapContextControlPane.SaveColorMapDialog.TITLE=Farbpalette speichern
+schmitzm.geotools.gui.MapContextControlPane.SaveColorMapDialog.QUESTION=Name für neue Farbpalette...
+schmitzm.geotools.gui.ColorMapTable.Header.QUANTITY=Raster-Wert
+schmitzm.geotools.gui.ColorMapTable.Header.COLOR=Farbe
+schmitzm.geotools.gui.ColorMapTable.Header.LABEL=Label
+schmitzm.geotools.gui.RasterPositionLabel.LABEL_PREFIX=Raster-Wert
+schmitzm.geotools.gui.GeotoolsGUIUtil.Load=Laden
+schmitzm.geotools.gui.GeotoolsGUIUtil.LoadRaster=Raster laden
+schmitzm.geotools.gui.GeotoolsGUIUtil.LoadFeature=Shape laden
+schmitzm.geotools.gui.GeotoolsGUIUtil.Save=Speichern
+schmitzm.geotools.gui.GeotoolsGUIUtil.SaveRaster=Raster speichern
+schmitzm.geotools.gui.GeotoolsGUIUtil.SaveFeature=Shape speichern
+schmitzm.geotools.gui.GeotoolsGUIUtil.NORTH=Nord
+schmitzm.geotools.gui.GeotoolsGUIUtil.SOUTH=Süd
+schmitzm.geotools.gui.GeotoolsGUIUtil.WEST=West
+schmitzm.geotools.gui.GeotoolsGUIUtil.EAST=Ost
+schmitzm.geotools.gui.GeotoolsGUIUtil.North=Norden
+schmitzm.geotools.gui.GeotoolsGUIUtil.South=Süden
+schmitzm.geotools.gui.GeotoolsGUIUtil.West=Westen
+schmitzm.geotools.gui.GeotoolsGUIUtil.East=Osten
+schmitzm.geotools.gui.GeotoolsGUIUtil.NORTH.Abb=N
+schmitzm.geotools.gui.GeotoolsGUIUtil.SOUTH.Abb=S
+schmitzm.geotools.gui.GeotoolsGUIUtil.WEST.Abb=W
+schmitzm.geotools.gui.GeotoolsGUIUtil.EAST.Abb=O
+schmitzm.geotools.gui.CRSSelectionDialog.init.crs.title=CRS datenbank
+schmitzm.geotools.gui.CRSSelectionDialog.init.crs.mess=CRS-Datenbank wird initialisiert. Bitte warten...
+schmitzm.geotools.gui.CRSSelectionDialog.title=Koordinaten-System (CRS) auswählen
+schmitzm.geotools.gui.CRSSelectionDialog.mandatory=CRS must be specified!
+schmitzm.geotools.gui.CRSSelectionDialog.button.wgs84=WGS-84 CRS
+schmitzm.geotools.gui.CRSSelectionDialog.button.default=Standard CRS (${0})
+schmitzm.geotools.gui.CRSSelectionDialog.button.predefined=Vordefiniert
+schmitzm.geotools.gui.CRSSelectionDialog.button.userDefined=Benutzerdefiniert:
+schmitzm.geotools.gui.JEditorPane.Err.MissingMap=Bevor ein neues Layer erstellt werden kann, muss ein Layer angezeigt werden (um CRS und geogr. Lage zu definieren).
+schmitzm.geotools.gui.JEditorPane.Err.Line.LessPoints=Für ein Line-Feature müssen mind. 2 Punkte definiert werden!
+schmitzm.geotools.gui.JEditorPane.Err.Polygon.LessPoints=Für ein Polygon-Feature müssen mind. 3 Punkte definiert werden!
+schmitzm.geotools.gui.JEditorToolBar.button.layer.new=Neues Layer erstellen
+schmitzm.geotools.gui.JEditorToolBar.button.layer.save=Layer abschliessen
+schmitzm.geotools.gui.JEditorToolBar.button.layer.cancel=Layer abbrechen
+schmitzm.geotools.gui.JEditorToolBar.button.edit.undo=Letzte Operation zurücknehmen
+schmitzm.geotools.gui.JEditorToolBar.button.edit.redo=Letzte zurückgenommene Operation wiederholen
+schmitzm.geotools.gui.JEditorToolBar.button.edit.clear=Layer leeren
+schmitzm.geotools.gui.JEditorToolBar.button.edit.finish=Neues Feature starten
+schmitzm.geotools.gui.JEditorToolBar.NewLayer.dialog.title=Neues Layer erzeugen
+schmitzm.geotools.gui.JEditorToolBar.NewLayer.layer.title=Layer-Bezeichnung
+schmitzm.geotools.gui.JEditorToolBar.NewLayer.layer.title.default=Neues Layer
+schmitzm.geotools.gui.JEditorToolBar.NewLayer.layer.type=Layer-Art
+schmitzm.geotools.gui.JEditorToolBar.NewLayer.layer.type.point=Punkt-Layer
+schmitzm.geotools.gui.JEditorToolBar.NewLayer.layer.type.line=Linien-Layer
+schmitzm.geotools.gui.JEditorToolBar.NewLayer.layer.type.polygon=Polygon-Layer
+schmitzm.geotools.gui.JEditorToolBar.NewLayer.ftype.title=Weitere Attribute
+schmitzm.geotools.gui.JEditorToolBar.NewLayer.Err.GeomAttr=Attribut-Name '${0}' reserviert für das Default-Geometrie-Attribut.
+schmitzm.geotools.gui.JEditorToolBar.NewLayer.Err.AutoVal=Auto-Wert für Attribut-Typ '${0}' nicht möglich.
+schmitzm.geotools.gui.JEditorToolBar.NewFeature.title=Neues Feature
+schmitzm.geotools.gui.StyleToolBar.FillColor=Füllfarbe
+schmitzm.geotools.gui.StyleToolBar.BorderColor=Randfarbe
+schmitzm.geotools.gui.StyleToolBar.BorderWidth=Randbreite
+schmitzm.geotools.gui.StyleToolBar.PointMark=Punkt-Style
+schmitzm.geotools.gui.FeatureTypeBuilderTableModel.AttrName=Name
+schmitzm.geotools.gui.FeatureTypeBuilderTableModel.AttrType=Typ
+schmitzm.geotools.gui.FeatureTypeBuilderTableModel.Nillable=Nullable
+schmitzm.geotools.gui.FeatureTypeBuilderTableModel.AutoValue=Auto-Wert
+schmitzm.geotools.gui.FeatureTypeBuilderTableModel.DefValue=Default
+schmitzm.geotools.gui.FeatureTypeBuilderTableModel.NewAttr=Attribut_${0}
+
+schmitzm.geotools.gui.SelectableFeatureTablePane.button.clearSelection.tt=Auswahl aufheben
+schmitzm.geotools.gui.SelectableFeatureTablePane.button.selectionToTop.tt=Ausgewählte Zeilen in der Tabelle nach oben verschieben 
+schmitzm.geotools.gui.SelectableFeatureTablePane.button.invertSelection.tt=Auswahl umkehren
+schmitzm.geotools.gui.SelectableFeatureTablePane.button.zoomToSelection.tt=Zoomt zu den ausgewählten Geoobjekten 
+schmitzm.geotools.gui.SelectableFeatureTablePane.selectionStatus=${0} von ${1} ${2} selektiert.
+schmitzm.geotools.gui.SelectableFeatureTablePane.selectionStatus.polygons=Polygonen
+schmitzm.geotools.gui.SelectableFeatureTablePane.selectionStatus.points=Punkten
+schmitzm.geotools.gui.SelectableFeatureTablePane.selectionStatus.lines=Linien

Modified: trunk/src/schmitzm/geotools/gui/resource/locales/GTResourceBundle_fr.properties
===================================================================
--- trunk/src/schmitzm/geotools/gui/resource/locales/GTResourceBundle_fr.properties	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/gui/resource/locales/GTResourceBundle_fr.properties	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,3 +1,32 @@
+##########
+#Copyright (c) 2009 Martin O. J. Schmitz.
+#
+#This file is part of the SCHMITZM library - a collection of utility 
+#classes based on Java 1.6, focussing (not only) on Java Swing 
+#and the Geotools library.
+#
+#The SCHMITZM project is hosted at:
+#http://wald.intevation.org/projects/schmitzm/
+#
+#This program is free software; you can redistribute it and/or
+#modify it under the terms of the GNU Lesser General Public License
+#as published by the Free Software Foundation; either version 3
+#of the License, or (at your option) any later version.
+#
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+#
+#You should have received a copy of the GNU Lesser General Public License (license.txt)
+#along with this program; if not, write to the Free Software
+#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#or try this link: http://www.gnu.org/licenses/lgpl.html
+#
+#Contributors:
+#    Martin O. J. Schmitz - initial API and implementation
+#    Stefan A. Krüger - additional utility classes
+##########
 # ----------------------------------------------------
 # ------ German Translations for GUI components ------
 # ------ in Package schmitz.geotools.gui        ------
@@ -112,4 +141,4 @@
 schmitzm.geotools.gui.SelectableFeatureTablePane.selectionStatus=Sélection: ${0} de ${1} ${2}
 schmitzm.geotools.gui.SelectableFeatureTablePane.selectionStatus.polygons=polygones
 schmitzm.geotools.gui.SelectableFeatureTablePane.selectionStatus.points=points
-schmitzm.geotools.gui.SelectableFeatureTablePane.selectionStatus.lines=lignes
\ No newline at end of file
+schmitzm.geotools.gui.SelectableFeatureTablePane.selectionStatus.lines=lignes

Modified: trunk/src/schmitzm/geotools/io/GeoExportUtil.java
===================================================================
--- trunk/src/schmitzm/geotools/io/GeoExportUtil.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/io/GeoExportUtil.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,291 +1,309 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.io;
-
-import java.awt.geom.Rectangle2D;
-import java.awt.image.BufferedImage;
-import java.awt.image.Raster;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.PrintWriter;
-
-import javax.imageio.ImageIO;
-
-import org.geotools.coverage.grid.GridCoverage2D;
-import org.geotools.data.FeatureSource;
-import org.geotools.data.FeatureStore;
-import org.geotools.data.Transaction;
-import org.geotools.data.shapefile.ShapefileDataStore;
-import org.geotools.feature.FeatureCollection;
-import org.geotools.gce.arcgrid.ArcGridRaster;
-import org.opengis.metadata.Identifier;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-
-import schmitzm.data.WritableGridRaster;
-import schmitzm.geotools.feature.FeatureCollectionReader;
-import schmitzm.io.IOUtil;
-
-/**
- * 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)
- * @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>
-   * <li>{@link FeatureSource            org.geotools.data.FeatureSource}</li>
-   * <li>{@link FeatureStore             org.geotools.data.FeatureStore}</li>
-   * <li>{@link Transaction              org.geotools.data.Transaction}</li>
-   * <li>{@link FeatureCollection        org.geotools.feature.FeatureCollection}</li>
-   * <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 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 source       = shpStore.getFeatureSource();
-      FeatureStore  featureStore = (FeatureStore)source;
-      // 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.ArcGridRaster}</li>
-   * <li>{@link java.awt.image.Raster}</li>
-   * <li>{@link java.awt.geom.Rectangle2D}</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 {
-    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);
-    // 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 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
-    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"));
-  }
-
-  /**
-   * 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.gce.arcgrid.ArcGridRaster}</li>
-   * </ul>
-   * </code>
-   * @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 {
-    // Exportieren
-    ArcGridRaster writer = new ArcGridRaster(new PrintWriter(new FileOutputStream(outFile)));
-    writer.writeRaster(grid, grid.getX(), grid.getY(), grid.getCellWidth(), false);
-    // 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]);
-
-    // 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}.
-	 * 
-	 * @param crs
-	 *            Koordinaten-System
-	 * @param output
-	 *            Datei in die die Projektion geschrieben wird
-	 * @exception IOException
-	 *                falls die Datei nicht geschrieben werden kann
-	 */
-	public static void writeProjectionFile(CoordinateReferenceSystem crs,
-			File output) throws IOException {
-		PrintWriter out = new PrintWriter(output);
-		out.println(crs.toWKT());
-		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.
-	 * 
-	 * @param crs
-	 *            Koordinaten-System
-	 * @param output
-	 *            Datei in die die Projektion geschrieben wird
-	 * @exception IOException
-	 *                falls die Datei nicht geschrieben werden kann
-	 */
-	public static void writeProjectionFilePrefereEPSG(
-			CoordinateReferenceSystem crs, File output) throws IOException {
-		PrintWriter out = new PrintWriter(output);
-
-		try {
-
-			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();
-					}
-				}
-			}
-
-			if (whatToWrite == null) {
-				/*
-				 * If we don't know the EPSG code for the CRS, save it as WKT
-				 */
-				whatToWrite = crs.toWKT();
-			}
-
-			out.println(whatToWrite);
-			out.flush();
-		} finally {
-			out.close();
-		}
-	}
-
-
-}
-
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.io;
+
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.Raster;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+import javax.imageio.ImageIO;
+
+import org.geotools.coverage.grid.GridCoverage2D;
+import org.geotools.data.FeatureSource;
+import org.geotools.data.FeatureStore;
+import org.geotools.data.Transaction;
+import org.geotools.data.shapefile.ShapefileDataStore;
+import org.geotools.feature.FeatureCollection;
+import org.geotools.gce.arcgrid.ArcGridRaster;
+import org.opengis.metadata.Identifier;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+
+import schmitzm.data.WritableGridRaster;
+import schmitzm.geotools.feature.FeatureCollectionReader;
+import schmitzm.io.IOUtil;
+
+/**
+ * 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)
+ * @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>
+   * <li>{@link FeatureSource            org.geotools.data.FeatureSource}</li>
+   * <li>{@link FeatureStore             org.geotools.data.FeatureStore}</li>
+   * <li>{@link Transaction              org.geotools.data.Transaction}</li>
+   * <li>{@link FeatureCollection        org.geotools.feature.FeatureCollection}</li>
+   * <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 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 source       = shpStore.getFeatureSource();
+      FeatureStore  featureStore = (FeatureStore)source;
+      // 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.ArcGridRaster}</li>
+   * <li>{@link java.awt.image.Raster}</li>
+   * <li>{@link java.awt.geom.Rectangle2D}</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 {
+    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);
+    // 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 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
+    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"));
+  }
+
+  /**
+   * 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.gce.arcgrid.ArcGridRaster}</li>
+   * </ul>
+   * </code>
+   * @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 {
+    // Exportieren
+    ArcGridRaster writer = new ArcGridRaster(new PrintWriter(new FileOutputStream(outFile)));
+    writer.writeRaster(grid, grid.getX(), grid.getY(), grid.getCellWidth(), false);
+    // 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]);
+
+    // 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}.
+	 * 
+	 * @param crs
+	 *            Koordinaten-System
+	 * @param output
+	 *            Datei in die die Projektion geschrieben wird
+	 * @exception IOException
+	 *                falls die Datei nicht geschrieben werden kann
+	 */
+	public static void writeProjectionFile(CoordinateReferenceSystem crs,
+			File output) throws IOException {
+		PrintWriter out = new PrintWriter(output);
+		out.println(crs.toWKT());
+		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.
+	 * 
+	 * @param crs
+	 *            Koordinaten-System
+	 * @param output
+	 *            Datei in die die Projektion geschrieben wird
+	 * @exception IOException
+	 *                falls die Datei nicht geschrieben werden kann
+	 */
+	public static void writeProjectionFilePrefereEPSG(
+			CoordinateReferenceSystem crs, File output) throws IOException {
+		PrintWriter out = new PrintWriter(output);
+
+		try {
+
+			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();
+					}
+				}
+			}
+
+			if (whatToWrite == null) {
+				/*
+				 * If we don't know the EPSG code for the CRS, save it as WKT
+				 */
+				whatToWrite = crs.toWKT();
+			}
+
+			out.println(whatToWrite);
+			out.flush();
+		} finally {
+			out.close();
+		}
+	}
+
+
+}
+

Modified: trunk/src/schmitzm/geotools/io/GeoImportUtil.java
===================================================================
--- trunk/src/schmitzm/geotools/io/GeoImportUtil.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/io/GeoImportUtil.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,867 +1,885 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.io;
-
-import java.awt.geom.Rectangle2D;
-import java.awt.image.BufferedImage;
-import java.awt.image.RenderedImage;
-import java.awt.image.WritableRaster;
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.net.URL;
-import java.nio.channels.FileChannel;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.StringTokenizer;
-import java.util.Vector;
-
-import javax.imageio.IIOException;
-import javax.imageio.ImageIO;
-
-import org.apache.log4j.Logger;
-import org.geotools.coverage.grid.GridCoverage2D;
-import org.geotools.coverage.grid.GridCoverageFactory;
-import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader;
-import org.geotools.data.DataStore;
-import org.geotools.data.shapefile.Lock;
-import org.geotools.data.shapefile.ShapefileDataStore;
-import org.geotools.data.shapefile.indexed.IndexedShapefileDataStore;
-import org.geotools.data.shapefile.shp.ShapefileReader;
-import org.geotools.factory.Hints;
-import org.geotools.feature.FeatureCollection;
-import org.geotools.feature.FeatureCollections;
-import org.geotools.gce.arcgrid.ArcGridRaster;
-import org.geotools.gce.geotiff.GeoTiffReader;
-import org.geotools.gce.image.WorldImageReader;
-import org.geotools.geometry.Envelope2D;
-import org.geotools.gui.swing.ExceptionMonitor;
-import org.geotools.referencing.CRS;
-import org.geotools.referencing.crs.DefaultGeographicCRS;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-
-import schmitzm.data.WritableGridRaster;
-import schmitzm.geotools.GTUtil;
-import schmitzm.io.IOUtil;
-
-import com.vividsolutions.jts.geom.Geometry;
-
-/**
- * In dieser Klasse sind Funktionen zum Datenimport von Geo-Daten
- * zusammengefasst.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class GeoImportUtil {
-  private static final Logger LOGGER = Logger.getLogger(GeoImportUtil.class.getName());
-
-  /** These postfixes are associated with Arc/Info ASCII Grid files
-   * TODO .0 habe ich auch schon gesehen. Nut leider kann man das nicht in einen enum packen.
-   * */
-	static public enum ARCASCII_POSTFIXES {
-		arc, dat, ascii, txt, asc, a00
-	};
-
-	/** These postfixes are associated with GeoTiff files */
-	static public enum GEOTIFF_POSTFIXES {
-		tif, tiff
-	};
-
-	/** These postfixes are associated with ESRI SHape files */
-	static public enum SHP_POSTFIXES {
-		shp, sbx, sbn, dbf, shx, 
-		qix, fix,	// Non-ESRI QuadTree Index stuff
-		cpg // Supported by ESRI. Contains the name of codepage used inside the DBF
-	};
-
-	/** These postfixes are associated with ordinary image files, excluding GeoTIFF endings please */
-	static public enum IMAGE_POSTFIXES {
-		png, gif, jpg, jpeg
-	};
-
-	/** These postfixes are associated with world files */
-	static public enum WORLD_POSTFIXES {
-		wld, jgw, pgw, tfw
-	};
-
-
-  /**
-   * Standard-CRS, welches verwendet wird, wenn beim Import kein CRS ermittelt
-   * werden kann (Default: {@link DefaultGeographicCRS#WGS84}).<br>
-   * <b>Achtung:</b><br>
-   * Anwendungen koennen diese Variable gefahrlos ueberschreiben, um ein fuer
-   * die Anwendung adaequates Standard-CRS zu verwenden.
-   */
-  public static CoordinateReferenceSystem DEFAULT_CRS = DefaultGeographicCRS.WGS84;
-
-  /**
-   * Diese Methode extrahiert saemtliche Features aus einem ShapeFile-Projekt
-   * (<code><i>name</i>.shp <i>name</i>.prj <i>name</i>.dbf ...</code>)
-   * und speichert diese in einer <code>org.geotools.feature.FeatureCollection</code>.<br>
-   *
-   * @param url {@link URL} to Shape-File
-   * @param prjUrl {@link URL} zu .prj Datei des Shape-File
-   *
-   *
-   * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
-   *
-   * @return {@link FeatureCollection} that was read
-   *
-   * @throws IOException
-   */
-  public static FeatureCollection readFeaturesFromShapeURL(URL url,
-			URL prjUrl) throws IOException {
-		ShapefileDataStore store = new ShapefileDataStore(url);
-		try {
-			// Testen, ob Projektion ermittelt werden kann, um vorab das
-			// Standard-CRS
-			// zu setzen
-			LOGGER.debug("  parseWKT on " + prjUrl);
-			CRS.parseWKT(readProjectionString(prjUrl));
-		} catch (Exception err) {
-			LOGGER.warn(" CRS.parseWKT mit Ex\n: ", err);
-			LOGGER.warn(" No projection found for file. Default is used.");
-			LOGGER
-					.warn(" NOT calling forceSchemaCRS now... please provide a URL to an existing .prj file!");
-			// store.forceSchemaCRS(DEFAULT_CRS);
-		}
-		String[] typeNames = store.getTypeNames();
-		FeatureCollection fc = store.getFeatureSource(typeNames[0])
-				.getFeatures();
-
-		// Create a new DefaultFeatureCollection to allow modifying
-	    // operations on the collection ("fc" is a DataFeatureCollection, whose
-	    // add(.) and remove(.) methods do nothing. Furthermore a FIDFeatureReader
-		// is used which returns copies of the features, so modifying the attributes
-		// does not effect the features in the collection!)
-	    FeatureCollection fc1 = FeatureCollections.newCollection( fc.getID() );
-	    fc1.addAll( fc );
-	    fc = fc1;
-
-	    return fc;
-	}
-
-
-  /**
-	 * Diese Methode extrahiert saemtliche Features aus einem ShapeFile-Projekt (<code><i>name</i>.shp <i>name</i>.prj <i>name</i>.dbf ...</code>)
-	 * und speichert diese in einer
-	 * <code>org.geotools.feature.FeatureCollection</code>.<br>
-	 *
-	 * @param file
-	 *            Shape-File
-	 * @throws java.lang.Exception
-	 *             bei irgendeinem Fehler
-	 *
-	 * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-	 *
-	 * TODO Wenn readFeaturesFromShapeURL getestet ist, dann sollte die hiet auf readFeaturesFromShapeURL(file.getURL) umgeleitet werden (SK)
-	 */
-  public static FeatureCollection readFeaturesFromShapeFile(File file) throws Exception {
-    ShapefileDataStore store   = new ShapefileDataStore(file.toURI().toURL());
-    File               prjFile = IOUtil.changeFileExt(file, "prj");
-    boolean            delPrjFile = false;
-    try {
-      // Testen, ob Projektion ermittelt werden kann, um vorab das Standard-CRS
-      // zu setzen
-      String prjString = readProjectionString(prjFile);
-      if ( prjString == null || prjString.trim().equals("") )
-        throw new FileNotFoundException("No proper prj-File exists: "+file.getName());
-      CRS.parseWKT(prjString);
-    } catch (FileNotFoundException err) {
-      store.forceSchemaCRS(getDEFAULT_CRS());
-      LOGGER.warn("No projection found for file "+file.getName()+". Default is used.");
-      delPrjFile = true; // von DataStore erzeugte Datei wieder loeschen
-    }
-    String[] typeNames = store.getTypeNames();
-    FeatureCollection fc = store.getFeatureSource(typeNames[0]).getFeatures();
-    if ( delPrjFile )
-      prjFile.delete();
-
-    // Create a new DefaultFeatureCollection to allow modifying
-    // operations on the collection ("fc" is a DataFeatureCollection, whose
-    // add(.) and remove(.) methods do nothing. Furthermore a FIDFeatureReader
-    // is used which returns copies of the features, so modifying the attributes
-    // does not effect the features in the collection!)
-    FeatureCollection fc1 = FeatureCollections.newCollection( fc.getID() );
-    fc1.addAll( fc );
-    fc = fc1;
-
-    return fc;
-  }
-
-
-  /**
-   * TODO DOKU
-   * @param shpURL
-   * @param prjURL
-   * @return
-   * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
- * @throws IOException
-   */
-  public static DataStore readDataStoreFromShape(URL shpURL, URL prjURL) throws IOException {
-	  Map map = new HashMap();
-	  map.put( "url", shpURL );
-	  map.put( "create spatial index", true );
-
-	  //DataStore dataStore = DataStoreFinder.getDataStore( map );
-	  DataStore dataStore = new IndexedShapefileDataStore(shpURL, null, false, true, IndexedShapefileDataStore.TREE_QIX);
-	  // DataStore dataStore = new ShapefileDataStore(shpURL);
-	  System.out.println("DataStore = "+dataStore.getClass().toString());
-	  IndexedShapefileDataStore dataStoreIndex = (IndexedShapefileDataStore)dataStore;
-	  System.out.println("indexed = "+dataStoreIndex.isIndexed());
-	  System.out.println("memory = "+dataStoreIndex.isMemoryMapped());
-  	return dataStore;
-  }
-
-
-  /**
-   * Diese Methode extrahiert saemtliche Geometrien aus einem ShapeFile-Projekt
-   * (<code><i>name</i>.shp <i>name</i>.prj <i>name</i>.dbf ...</code>)
-   * und speichert diese in einer Liste (Vector) von {@link com.vividsolutions.jts.geom.Geometry}-Objekten.<br>
-   * Baut auf folgenden Geotools-Klassen auf:
-   * <code>
-   * <ul>
-   * <li>{@link ShapefileReader org.geotools.data.shapefile.shp.ShapefileReader}</li>
-   * <li>{@link Geometry        com.vividsolutions.jts.geom.Geometry}</li>
-   * </ul>
-   * </code>
-   * @param file Shape-File
-   * @throws java.lang.Exception bei irgendeinem Fehler
-   */
-  public static Vector<Geometry> readGeometriesFromShapeFile(File file) throws Exception {
-    FileChannel in = new FileInputStream(file).getChannel();
-    ShapefileReader r = new ShapefileReader( in, new Lock() );
-    Vector<Geometry> geomList = new Vector<Geometry>();
-    for(int i=1; r.hasNext(); i++) {
-        //        org.geotools.renderer.geom.Geometry shape = (org.geotools.renderer.geom.Geometry) r.nextRecord().shape();
-        //        org.geotools.geometry.Geometry shape = (org.geotools.geometry.Geometry) r.nextRecord().shape();
-        Object obj = r.nextRecord().shape();
-        Geometry shape = (Geometry)obj;
-        geomList.add(shape);
-      }
-      r.close();
-      return geomList;
-    }
-
-    /**
-     * Diese Methode importiert ein Raster aus einer Datei im ArcInfoASCII-Grid-Format.
-     * Das CRS wird aus einem prj-File (EPSG-Code "EPSG:..." oder WKT-Definition)
-     * gelesen. Ist dies nicht erfolgreich, wird {@link #DEFAULT_CRS}
-     * als CRS verwendet.
-     * @param file ASCII-File
-     * @throws java.lang.Exception bei irgendeinem Fehler
-     * @return {@link GridCoverage2D}
-     */
-    public static GridCoverage2D readGridFromArcInfoASCII(File file) throws Exception {
-      return readGridFromArcInfoASCII(file,null);
-    }
-
-    /**
-     * Diese Methode importiert ein Raster aus einer Datei im ArcInfoASCII-Grid-Format.
-     * Wenn kein CRS angegeben wird, wird versucht das CRS aus einem prj-File
-     * (EPSG-Code "EPSG:..." oder WKT-Definition) zu lesen. Ist dies nicht
-     * erfolgreich, wird {@link #DEFAULT_CRS} als CRS verwendet.
-     * @param file ASCII-File
-     * @param crs CoordinateReferenceSystem fuer das Raster (kann {@code null} sein)
-     * @throws java.lang.Exception bei irgendeinem Fehler
-     * TODO
-     */
-    public static GridCoverage2D readGridFromArcInfoASCII(File file, CoordinateReferenceSystem crs) throws Exception {
-    	return readGridFromArcInfoASCII(file.toURI().toURL(), crs);
-
-//      ArcGridRaster  reader = new ArcGridRaster( new BufferedReader( new InputStreamReader( new FileInputStream(file) ) ), false );
-//      WritableRaster raster = reader.readRaster();
-//      if (crs == null)
-//        crs = determineProjection(file);
-//
-////      System.out.println("Position  "+reader.getXlCorner()+" / "+reader.getYlCorner());
-////      System.out.println("Size      "+reader.getNCols()+" / "+reader.getNRows());
-////      System.out.println("Min/Max   "+reader.getMinValue()+" / "+reader.getMaxValue());
-////      System.out.println("NoData    "+reader.getNoData());
-////      System.out.println("CellSize  "+reader.getCellSize());
-//
-//      float x = (float) reader.getXlCorner(); // Suedwestliche Ecke!
-//      float y = (float) reader.getYlCorner(); // Suedwestliche Ecke!
-//      float w = (float) (reader.getNCols() * reader.getCellSize()); // reale Breite = RasterSpalten * Aufloesung
-//      float h = (float) (reader.getNRows() * reader.getCellSize()); // reale Hoehe = RasterZeilen * Aufloesung
-//      Envelope2D envelope = new Envelope2D(crs, new Rectangle2D.Float(x, y, w, h));
-//
-//      // WICHTIG: Name des Rasters sollte Leer-String sein, da ansonsten das
-//      //          Coloring des Rasters nicht klappt.
-//      //          --> Name der Categories muss (warum auch immer) mit dem Namen
-//      //              des Rasters uebereinstimmen!!!
-//      return new GridCoverageFactory().create("", raster, envelope);
-////
-////=== OHNE ArcGridRaster ===
-//////      ArcGridReader reader = new ArcGridReader( new BufferedReader( new InputStreamReader( new FileInputStream(file) ) ));
-////      ArcGridReader reader = new ArcGridReader( file );
-////      return (GridCoverage2D)reader.read(null);
-    }
-
-
-    /**
-     * Diese Methode importiert ein Raster aus einer Datei im ArcInfoASCII-Grid-Format.
-     * Wenn kein CRS angegeben wird, wird versucht das CRS aus einem prj-File
-     * (EPSG-Code "EPSG:..." oder WKT-Definition) zu lesen. Ist dies nicht
-     * erfolgreich, wird {@link #DEFAULT_CRS} als CRS verwendet.
-     * @param url Link to Arc/Info GRID ASCII file
-     * @param crs CoordinateReferenceSystem fuer das Raster (kann {@code null} sein)
-     * @throws java.lang.Exception bei irgendeinem Fehler
-     */
-    public static GridCoverage2D readGridFromArcInfoASCII(URL url, CoordinateReferenceSystem crs) throws Exception {
-      ArcGridRaster  reader = new ArcGridRaster( new BufferedReader( new InputStreamReader(url.openStream()) ), false );
-      WritableRaster raster = reader.readRaster();
-      if (crs == null)
-        crs = determineProjection( IOUtil.changeUrlExt(url,"prj"));
-
-//      System.out.println("Position  "+reader.getXlCorner()+" / "+reader.getYlCorner());
-//      System.out.println("Size      "+reader.getNCols()+" / "+reader.getNRows());
-//      System.out.println("Min/Max   "+reader.getMinValue()+" / "+reader.getMaxValue());
-//      System.out.println("NoData    "+reader.getNoData());
-//      System.out.println("CellSize  "+reader.getCellSize());
-
-      float x = (float) reader.getXlCorner(); // Suedwestliche Ecke!
-      float y = (float) reader.getYlCorner(); // Suedwestliche Ecke!
-      float w = (float) (reader.getNCols() * reader.getCellSize()); // reale Breite = RasterSpalten * Aufloesung
-      float h = (float) (reader.getNRows() * reader.getCellSize()); // reale Hoehe = RasterZeilen * Aufloesung
-      Envelope2D envelope = new Envelope2D(crs, new Rectangle2D.Float(x, y, w, h));
-
-      // WICHTIG: Name des Rasters sollte Leer-String sein, da ansonsten das
-      //          Coloring des Rasters nicht klappt.
-      //          --> Name der Categories muss (warum auch immer) mit dem Namen
-      //              des Rasters uebereinstimmen!!!
-      return new GridCoverageFactory().create("", raster, envelope);
-//
-//=== OHNE ArcGridRaster ===
-////      ArcGridReader reader = new ArcGridReader( new BufferedReader( new InputStreamReader( new FileInputStream(file) ) ));
-//      ArcGridReader reader = new ArcGridReader( file );
-//      return (GridCoverage2D)reader.read(null);
-    }
-
-
-
-
-
-    /**
-     * Diese Methode erzeugt einen {@link AbstractGridCoverage2DReader} aus einer
-     * Datei im GeoTIFF-Format.
-     * Zunaechst wird versucht, die Geo-Informationen (Referenz+CRS) aus den
-     * TIFF-Metadaten zu ermitteln. Ist dies nicht erfolgreich, werden
-     * ein gleichnamiges World-File (.tfw) und Projection-File (.prj)
-     * herangezogen (siehe {@link WorldImageReader}).
-     * @param file GeoTIFF-File
-     * @param crs erzwungenes CoordinateReferenceSystem fuer das Raster (kann {@code null} sein)
-     * @throws java.lang.Exception bei irgendeinem Fehler
-     * @deprecated {@link WorldImageReader} klappt noch nicht so 100%ig (Colorisierung schlaegt fehl!)
-     */
-    public static AbstractGridCoverage2DReader createGridReaderFromGeoTiff(File file, CoordinateReferenceSystem crs) throws Exception {
-      // Versuchen Geo-Information aus Tiff zu lesen
-      try {
-        Hints hints = new Hints(null);
-        // Wenn CRS angegeben, dieses durch Hint erzwingen
-        if ( crs != null )
-          hints.put( Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM, crs );
-        // Reader (mit Metadaten) erzeugen
-        GeoTiffReader reader = new GeoTiffReader(file,hints);
-        // Wenn kein Referenzsystem vorhanden, versuchen ein prj-File zu verwenden
-        if ( reader.getOriginalEnvelope().getCoordinateReferenceSystem() == null ) {
-          LOGGER.warn("No projection information found in '"+file.getName()+"'. Using prj-file...");
-          hints.put( Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM, determineProjection(file) );
-          reader = new GeoTiffReader(file,hints);
-        }
-        return reader;
-      } catch ( UnsupportedOperationException err )  {
-        // erwartet, wenn keine Geo-Information im Tiff vorhanden ist
-      } catch ( NullPointerException err ) {
-        // erwartet, wenn keine Geo-Information im Tiff vorhanden ist
-      }
-
-      // keine Geo-Informationen in Tiff
-      // --> Raster ueber ImageIO einlesen und WorldFile/ProjectionFile verwenden
-      LOGGER.warn("No geo information found in '" + file.getName() +  "'. Using world- and prj-file...");
-      // @todo check the work of WorldImageReader with colorization!
-      throw new UnsupportedOperationException("WorldImageReader does not work well, yet... AbstractGridCoverage2DReader can not be created from this Tiff!");
-//      Hints hints = new Hints(null);
-//      // Wenn CRS angegeben, dieses durch Hint erzwingen
-//      if ( crs != null )
-//        hints.put( Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM, crs );
-//      WorldImageReader reader = new WorldImageReader(file);
-//      return reader;
-    }
-
-    /**
-     * Diese Methode erzeugt einen {@link AbstractGridCoverage2DReader} aus einer
-     * Datei im GeoTIFF-Format.
-     * @param file GeoTIFF-File
-     * @throws java.lang.Exception bei irgendeinem Fehler
-     * @see #createGridReaderFromGeoTiff(File, CoordinateReferenceSystem)
-     * @deprecated {@link WorldImageReader} klappt noch nicht so 100%ig (Colorisierung schlaegt fehl!)
-     */
-    public static AbstractGridCoverage2DReader createGridReaderFromGeoTiff(File file) throws Exception {
-      return createGridReaderFromGeoTiff(file,null);
-    }
-
-    /**
-    * Diese Methode importiert ein Raster aus einer Datei im GeoTIFF-Format.
-    * @param file GeoTIFF-File
-    * @param crs erzwungenes CoordinateReferenceSystem fuer das Raster (kann {@code null} sein)
-    * @throws java.lang.Exception bei irgendeinem Fehler
-    * @see #createGridReaderFromGeoTiff(File, CoordinateReferenceSystem)
-    */
-   public static GridCoverage2D readGridFromGeoTiff(File file, CoordinateReferenceSystem crs) throws Exception {
-//     return (GridCoverage2D)createGridReaderFromGeoTiff(file, crs).read(null);
-     GridCoverage2D gc = null;
-     // Versuchen Geo-Information aus Tiff zu lesen
-     try {
-       Hints hints = new Hints(null);
-
-       // Wenn CRS angegeben, dieses durch Hint erzwingen
-       if ( crs != null )
-         hints.put( Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM, crs );
-       // Reader (mit Metadaten) erzeugen
-       GeoTiffReader reader = new GeoTiffReader(file,hints);
-       // Wenn kein Referenzsystem vorhanden, versuchen ein prj-File zu verwenden
-       if ( reader.getOriginalEnvelope().getCoordinateReferenceSystem() == null ) {
-         LOGGER.warn("No projection information found in '"+file.getName()+"'. Using prj-file...");
-         hints.put( Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM, determineProjection(file) );
-         reader = new GeoTiffReader(file,hints);
-       }
-       gc = (GridCoverage2D)reader.read(null);
-       return gc;
-     } catch ( UnsupportedOperationException err )  {
-    	 // erwartet, wenn keine Geo-Information im Tiff vorhanden ist
-//    	 ExceptionMonitor.show(null, err, "No geoinformation in TIFF, importing it as a normal file. Trying to read it as normal TIFF + Worldfile.");
-     } catch ( NullPointerException err ) {
-       // erwartet, wenn keine Geo-Information im Tiff vorhanden ist
-     }
-
-     // keine Geo-Informationen in Tiff
-     // --> Raster ueber ImageIO einlesen und WorldFile/ProjectionFile verwenden
-     LOGGER.warn("No geo information found in '" + file.getName() +
-                 "'. Using world- and prj-file...");
-     BufferedImage im = ImageIO.read(file);
-     if (im == null)
-       throw new IIOException("No image reader found for this image type!");
-     // World-File einlesen
-     File tfw = IOUtil.changeFileExt(file, "tfw");
-     double[] tfwInfo = readWorldFile(tfw);
-     float w = (float) (im.getWidth() * tfwInfo[0]); // reale Breite = RasterSpalten * hor. Aufloesung
-     float h = (float) (im.getHeight() * ( -tfwInfo[3])); // reale Hoehe = RasterZeilen * vert. Aufloesung
-     float x = (float) tfwInfo[4]; // Suedwestliche Ecke!
-     float y = (float) tfwInfo[5] - h; // Suedwestliche Ecke (im tfw-File steht die Nordwestliche!)
-     // ggf. Projektion einlesen
-     if (crs == null)
-       crs = determineProjection(file);
-     Envelope2D envelope = new Envelope2D(crs, new Rectangle2D.Float(x, y, w, h));
-     // WICHTIG: Name des Rasters sollte Leer-String sein, da ansonsten das
-     //          Coloring des Rasters nicht klappt.
-     //          --> Name der Categories muss (warum auch immer) mit dem Namen
-     //              des Rasters uebereinstimmen!!!
-     gc = new GridCoverageFactory().create("", im.copyData(null), envelope);
-     return gc;
-   }
-
-   /**
-    * Diese Methode importiert ein Raster aus einer Datei im GeoTIFF-Format.
-    * @param file GeoTIFF-File
-    * @throws java.lang.Exception bei irgendeinem Fehler
-    * @see #readGridFromGeoTiff(File, CoordinateReferenceSystem)
-    */
-   public static GridCoverage2D readGridFromGeoTiff(File file) throws Exception {
-     return readGridFromGeoTiff(file,null);
-   }
-
-   /**
-    * Diese Methode importiert ein Raster aus einer Datei im ArcInfoASCII-Grid-Format.
-    * Das CRS wird aus einem prj-File (EPSG-Code "EPSG:..." oder WKT-Definition)
-    * gelesen. Ist dies nicht erfolgreich, wird {@link #DEFAULT_CRS}
-    * als CRS verwendet.
-    * @param file ASCII-File
-    * @throws java.lang.Exception bei irgendeinem Fehler
-    */
-   public static WritableGridRaster readGridRasterFromArcInfoASCII(File file) throws Exception {
-     return readGridRasterFromArcInfoASCII(file,null);
-   }
-
-   /**
-    * Diese Methode importiert ein Raster aus einer Datei im ArcInfoASCII-Grid-Format.
-    * Wenn kein CRS angegeben wird, wird versucht das CRS aus einem prj-File
-    * (EPSG-Code "EPSG:..." oder WKT-Definition) zu lesen. Ist dies nicht
-    * erfolgreich, wird {@link #DEFAULT_CRS} als CRS verwendet.
-    * @param file ASCII-File
-    * @param crs CoordinateReferenceSystem fuer das Raster (kann {@code null} sein)
-    * @throws java.lang.Exception bei irgendeinem Fehler
-    */
-   public static WritableGridRaster readGridRasterFromArcInfoASCII(File file, CoordinateReferenceSystem crs) throws Exception {
-     ArcGridRaster  reader = new ArcGridRaster(new BufferedReader(new InputStreamReader(new FileInputStream(file))),false);
-     WritableRaster raster = reader.readRaster();
-     float x = (float)reader.getXlCorner(); // Suedwestliche Ecke!
-     float y = (float)reader.getYlCorner(); // Suedwestliche Ecke!
-     float w = (float)(reader.getNCols() * reader.getCellSize()); // reale Breite = RasterSpalten * Aufloesung
-     float h = (float)(reader.getNRows() * reader.getCellSize()); // reale Hoehe = RasterZeilen * Aufloesung
-     // Projektion einlesen
-     if (crs == null)
-       crs = determineProjection(file);
-     return new WritableGridRaster(raster, new Rectangle2D.Float(x,y,w,h), crs );
-
-//=== OHNE ArcGridRaster ===
-//     GridCoverage2D grid   = readGridFromArcInfoASCII(null,input);
-//     WritableRaster raster = grid.getRenderedImage().copyData(null);
-//     return( new WritableGridRaster(raster,grid.getEnvelope2D()) );
-   }
-
-   /**
-    * Diese Methode importiert ein Raster aus einer Datei im GeoTIFF-Format.
-    * Zunaechst wird versucht, die Geo-Informationen (Referenz+CRS) aus den
-    * TIFF-Metadaten zu ermitteln. Ist dies nicht erfolgreich, werden
-    * ein gleichnamiges World-File (.tfw) und Projection-File (.prj)
-    * herangezogen. Als Projektion (.prj) ist sowohl ein EPSG-Code "EPSG:...",
-    * als auch eine WKT-Definition erlaubt. Kann kein CRS ermitteln werden,
-    * wird {@link #DEFAULT_CRS} als CRS verwendet.
-    * @param file GeoTIFF-File
-    * @throws java.lang.Exception bei irgendeinem Fehler
-     */
-   public static WritableGridRaster readGridRasterFromGeoTiff(File file) throws Exception {
-     return readGridRasterFromGeoTiff(file,null);
-   }
-
-   /**
-    * Diese Methode importiert ein Raster aus einer Datei im GeoTIFF-Format.
-    * Zunaechst wird versucht, die Geo-Informationen (Referenz+CRS) aus den
-    * TIFF-Metadaten zu ermitteln. Ist dies nicht erfolgreich, werden
-    * ein gleichnamiges World-File (.tfw) und Projection-File (.prj)
-    * herangezogen. Als Projektion (.prj) ist sowohl ein EPSG-Code "EPSG:...",
-    * als auch eine WKT-Definition erlaubt. Kann kein CRS ermitteln werden,
-    * wird {@link #DEFAULT_CRS} als CRS verwendet.
-    * @param file GeoTIFF-File
-    * @param crs erzwungenes CoordinateReferenceSystem fuer das Raster (kann {@code null} sein)
-    * @throws java.lang.Exception bei irgendeinem Fehler
-    */
-  public static WritableGridRaster readGridRasterFromGeoTiff(File file, CoordinateReferenceSystem crs) throws Exception {
-//    // GeoTiff-File einlesen
-//    BufferedImage im = ImageIO.read( file );
-//    if ( im == null )
-//      throw new IIOException("No image reader found for this image type!");
-//    // World-File einlesen
-//    File tfw = IOUtil.changeFileExt(file,"tfw");
-//    double[] tfwInfo = readWorldFile(tfw);
-//    // ggf. Projektion einlesen
-//    if (crs == null)
-//      crs = determineProjection(file);
-//
-//    float w = (float) (im.getWidth() * tfwInfo[0]); // reale Breite = RasterSpalten * hor. Aufloesung
-//    float h = (float) (im.getHeight() * (-tfwInfo[3])); // reale Hoehe = RasterZeilen * vert. Aufloesung
-//    float x = (float) tfwInfo[4]; // Suedwestliche Ecke!
-//    float y = (float) tfwInfo[5] - h ; // Suedwestliche Ecke (im tfw-File steht die Nordwestliche!)
-//
-//    Rectangle2D        env    = new Rectangle2D.Float(x,y,w,h);
-//    WritableGridRaster raster = new WritableGridRaster(
-//      im.getData().getDataBuffer().getDataType(),
-//      0,
-//      0,
-//      im.getWidth(),
-//      im.getHeight(),
-//      env,
-//      crs
-//    );
-//
-
-    GridCoverage2D gc  = readGridFromGeoTiff(file,crs);
-    Rectangle2D    env = gc.getEnvelope2D();
-    RenderedImage  im  = gc.getRenderedImage();
-    WritableGridRaster raster = new WritableGridRaster(
-      im.getData().getDataBuffer().getDataType(),
-      0,
-      0,
-      im.getWidth(),
-      im.getHeight(),
-      env,
-      crs
-    );
-
-    im.copyData(raster);
-
-    return raster;
-  }
-
-  /**
-   * Liest ein World-File (.tfw) ein und liefert die darin zeilenweise
-   * gespeicherten Werte zurueck. Leer- und Kommentarzeilen werden dabei
-   * ignoriert. Kann ein Zeilen-Wert nicht in einen <code>double</code>
-   * umgewandelt werden, wird diese Zeile ignoriert, als 1.0 interpretiert
-   * und eine Meldung in die Standard-Fehler-Ausgabe geschrieben.<br>
-   * Der zurueckgegebene Array hat mindestens die Groesse 6:<br>
-   * <ol>
-   *    <li>Zellengroesse in X-Richtung (in Meter)</li>
-   *   <li>Koeffizient fuer Rotation in Y-Richtung</li>
-   *   <li>Koeffizient fuer Rotation in X-Richtung</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>
-   * @todo WorldFile-Spec vervollstaendigen
-   * @param file World-File
-   * @exception IOException falls die Datei nicht existiert oder ein unerwarteter
-   *            Fehler beim Einlesen auftritt
-   * @see IOUtil#isCommentLine(String)
-   * @see System#err
-   */
-
-   public static double[] readWorldFile(File file) throws IOException {
-     return readWorldFile(  new FileInputStream(file) ) ;
-   }
-
-
-   /**
-    * Liest ein World-File (.tfw) ein und liefert die darin zeilenweise
-    * gespeicherten Werte zurueck. Leer- und Kommentarzeilen werden dabei
-    * ignoriert. Kann ein Zeilen-Wert nicht in einen <code>double</code>
-    * umgewandelt werden, wird diese Zeile ignoriert, als 1.0 interpretiert
-    * und eine Meldung in die Standard-Fehler-Ausgabe geschrieben.<br>
-    * Der zurueckgegebene Array hat mindestens die Groesse 6:<br>
-    * <ol>
-    *    <li>Zellengroesse in X-Richtung (in Meter)</li>
-    *   <li>Koeffizient fuer Rotation in Y-Richtung</li>
-    *   <li>Koeffizient fuer Rotation in X-Richtung</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>
-    * @todo WorldFile-Spec vervollstaendigen
-    *
-    * @param inputStream Stream of World-File
-    * @exception IOException falls die Datei nicht existiert oder ein unerwarteter
-    *            Fehler beim Einlesen auftritt
-    * @see IOUtil#isCommentLine(String)
-    * @see System#err
-    *
-    * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-    * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
-    */
-   public static double[] readWorldFile(InputStream inputStream) throws IOException {
-	   Vector<Double> tfwValues = new Vector<Double>();
-	   BufferedReader in = new BufferedReader( new InputStreamReader( inputStream ) );
-	   String line = null;
-	   for(int lineNo=1; in.ready() && (line=in.readLine().trim()) != null; lineNo++ ) {
-		   if ( IOUtil.isCommentLine(line) || line.equals("") )
-			   continue;
-		   try {
-			   StringTokenizer st = new StringTokenizer(line);
-			   tfwValues.add( Double.parseDouble( st.nextToken(" \n;,#|/") ) );
-		   } catch (Exception err) {
-			   System.err.println("WorldFile-Error in line "+lineNo+": "+err);
-
-//		(SK)   System.err.println("WorldFile-Error in '"+file.getAbsolutePath()+"' (line "+lineNo+"): "+err);
-			   System.err.println("   >> expected value is set to 1.0");
-			   tfwValues.add( 1.0 );
-		   }
-	   }
-
-	   while ( tfwValues.size() < 6 ) {
-		   System.err.println("WorldFile-Error: value "+tfwValues.size()+" missing!");
-//		(SK)   System.err.println("WorldFile-Error in '"+file.getAbsolutePath()+"': value "+tfwValues.size()+" missing!");
-		   System.err.println("   >> expected value is set to 1.0");
-		   tfwValues.add( 1.0 );
-	   }
-
-	   // Vector in Array umwandeln
-	   double[] ret = new double[tfwValues.size()];
-	   for (int i=0; i<ret.length; i++)
-		   ret[i] = tfwValues.elementAt(i);
-	   return ret;
-   }
-
-   /**
-    * Liest das CRS aus einer Datei. Zunaechst wird versucht das CRS aus der
-    * uebergebene Datei zu lesen. Ist dies nicht erfolgreich wird das zur
-    * Datei korrespondierende prj-File herangezogen.
-    * @param file Datei
-    * @return {@code null}, wenn kein CRS gelesen werden konnte
-    */
-   public static CoordinateReferenceSystem determineProjection(File file) throws IOException {
-
-	//****************************************************************************
-	// schonmal teilweise migriert... das geht direkt an die URL methode weiter...
-	//****************************************************************************
-
-//     CoordinateReferenceSystem crs = null;
-//     // Versuchen CRS aus angegebener Datei zu lesen
-//     crs = readProjectionFile(file);
-//     // Wenn nicht erfolgreich versuchen die zur Datei korrespondierende
-//     // prj-Datei einzulesen
-//     if ( crs == null )
-//       crs = readProjectionFile( IOUtil.changeFileExt(file,"prj") );
-//     // Wenn nicht erfolgreich, Default verwenden
-//     if ( crs == null ) {
-//       LOGGER.warn("No projection found for file '"+file.getName()+"'. Default CRS used.");
-//       crs = DEFAULT_CRS;
-//     }
-     return determineProjection(file.toURI().toURL());
-   }
-
-
-	/**
-	 * Liest das CRS aus einer URL. Wenn keine CRS gelesen werden kann, dann
-	 * wird die Endung der URL gegen .prj gewechselt und nochmal versucht bevor
-	 * das {@link #DEFAULT_CRS} benutzt wird.
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public static CoordinateReferenceSystem determineProjection(URL prjUrl) {
-		CoordinateReferenceSystem crs = null;
-		// Versuchen CRS aus angegebener Datei zu lesen
-
-		LOGGER.debug("determineProjection: Try to read a projection from URL "
-				+ prjUrl);
-		try {
-			crs = GeoImportUtil.readProjectionFile(prjUrl);
-		} catch (IOException e) {
-		}
-
-		if (crs == null) {
-			try {
-				crs = GeoImportUtil.readProjectionFile(IOUtil.changeUrlExt(
-						prjUrl, "prj"));
-			} catch (IllegalArgumentException e) {
-			} catch (IOException e) {
-			}
-		}
-
-		// Wenn nicht erfolgreich, Default verwenden
-		if (crs == null) {
-			LOGGER.warn("No projection found in URL. Default CRS used.");
-			crs = getDEFAULT_CRS();
-		}
-		return crs;
-	}
-
-
-   /**
-    * Liest ein CRS aus einer URL. Als Dateiinhalt wird entweder ein
-    * EPSG-Code oder eine WKT-Definition des CRS akzeptiert.
-    * @param prjURL prj-Datei in der die Projektion hinterlegt ist
-    * @return {@code null}, wenn kein CRS gelesen werden konnte
-    * @see GTUtil#createCRS(String)
-    *
-    * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-    * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
-    * @throws IOException falls die URL nicht wie erwartet gelesen werden konnte.
-    */
-   public static CoordinateReferenceSystem readProjectionFile(URL prjURL) throws IOException {
-	   String crsDefinition = readProjectionString(prjURL);
-	   CoordinateReferenceSystem crs = GTUtil.createCRS( crsDefinition );
-	   return crs;
-   }
-
-   /**
-    * Liest ein CRS aus einer Datei. Als Dateiinhalt wird entweder ein
-    * EPSG-Code oder eine WKT-Definition des CRS akzeptiert.
-    * @param prjFile prj-Datei in der die Projektion hinterlegt ist
-    * @return {@code null}, wenn kein CRS gelesen werden konnte
-    * @see GTUtil#createCRS(String)
-    *
-    * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-    */
-   public static CoordinateReferenceSystem readProjectionFile(File prjFile) throws IOException {
-     String crsDefinition = readProjectionString(prjFile);
-     CoordinateReferenceSystem crs = GTUtil.createCRS( crsDefinition );
-//     if ( crs == null )
-//       LOGGER.warn("CRS can not be read from file '"+(prjFile == null ? "null" : prjFile.getName())+"'");
-     return crs;
-   }
-
-   /**
-    * Liest die ersten Zeilen der angegebenen prj-Datei und fuegt sie zu einem
-    * String zusammen. Wenn die Datei zu gross ist, wird ein Leerstring zurueckgegeben,
-    * da es sich dann nicht um eine Projektionsdefinition handelt.
-    * @param prjFile prj-Datei
-    * @return Leerstring, falls die Datei nicht existiert oder groesser als 10KB ist
-    *
-    * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-    */
-   private static String readProjectionString(File prjFile) throws IOException {
-     // Wenn Datei groesser als 10KB, dann ist es kein prj-File
-     if ( !prjFile.exists() || !prjFile.isFile() ||
-          prjFile.length() == 0 || prjFile.length() > 10240 )
-       return "";
-
-     // Alle Zeilen der Datei aneinander haengen
-     BufferedReader input = new BufferedReader( new InputStreamReader( new FileInputStream(prjFile) ) );
-     StringBuffer buffer = new StringBuffer();
-     String line = null;
-     while( input.ready() && (line = input.readLine()) != null )
-       if ( !IOUtil.isCommentLine(line) )
-         buffer.append(" ").append(line);
-     input.close();
-     return buffer.toString().trim();
-
-   }
-
-   /**
-    * Liest alle Zeilen aus der prj-Datei URL und fuegt diese zu einem
-    * String zusammen
-    *
-    * Kommentarzeilen werden ignoriert.
-    *
-    * Wenn mehr als 3000 Zeichen (ohne Kommentare) gelesen werden, wird davon
-    * ausgegangen, dass es sich nicht um eine .PRJ Datei handelt, und "" wird
-    * zurückgegeben.
-    *
-    * @param url {@link URL} auf prj-Datei
-    *
-    * @return Leerstring, wenn url == null
-    *
-    * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
-    */
-   public static String readProjectionString(URL url) throws IOException {
-     if (url == null) {
-       LOGGER.debug("readProjectionString returned empty String for url==null");
-       return "";
-     }
-
-     BufferedReader input = new BufferedReader(new InputStreamReader(url.openStream()));
-     try {
-         // Alle Zeilen der Datei aneinander haengen
-         StringBuffer buffer = new StringBuffer();
-         String line = null;
-         while (input.ready() && (line = input.readLine()) != null) {
-           if (!IOUtil.isCommentLine(line))
-             buffer.append(" ").append(line);
-           if (buffer.length() > 3000) {
-//             LOGGER.warn("The URL " + url + " doesn't seem point to a .prj file, because size is > 3000 characters. Returning \"\"");
-             return "";
-           }
-         }
-         final String prjString = buffer.toString().trim();
-         // LOGGER.debug("This is the PRJ String from URL = \n"+prjString);
-         return prjString;
-       } finally {
-         input.close();
-       }
-     }
-
-
-public static void setDEFAULT_CRS(CoordinateReferenceSystem dEFAULT_CRS) {
-	DEFAULT_CRS = dEFAULT_CRS;
-}
-
-
-public static CoordinateReferenceSystem getDEFAULT_CRS() {
-	return DEFAULT_CRS;
-}
-
-   }
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.io;
+
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.awt.image.RenderedImage;
+import java.awt.image.WritableRaster;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.net.URL;
+import java.nio.channels.FileChannel;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+import javax.imageio.IIOException;
+import javax.imageio.ImageIO;
+
+import org.apache.log4j.Logger;
+import org.geotools.coverage.grid.GridCoverage2D;
+import org.geotools.coverage.grid.GridCoverageFactory;
+import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader;
+import org.geotools.data.DataStore;
+import org.geotools.data.shapefile.Lock;
+import org.geotools.data.shapefile.ShapefileDataStore;
+import org.geotools.data.shapefile.indexed.IndexedShapefileDataStore;
+import org.geotools.data.shapefile.shp.ShapefileReader;
+import org.geotools.factory.Hints;
+import org.geotools.feature.FeatureCollection;
+import org.geotools.feature.FeatureCollections;
+import org.geotools.gce.arcgrid.ArcGridRaster;
+import org.geotools.gce.geotiff.GeoTiffReader;
+import org.geotools.gce.image.WorldImageReader;
+import org.geotools.geometry.Envelope2D;
+import org.geotools.gui.swing.ExceptionMonitor;
+import org.geotools.referencing.CRS;
+import org.geotools.referencing.crs.DefaultGeographicCRS;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+
+import schmitzm.data.WritableGridRaster;
+import schmitzm.geotools.GTUtil;
+import schmitzm.io.IOUtil;
+
+import com.vividsolutions.jts.geom.Geometry;
+
+/**
+ * In dieser Klasse sind Funktionen zum Datenimport von Geo-Daten
+ * zusammengefasst.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class GeoImportUtil {
+  private static final Logger LOGGER = Logger.getLogger(GeoImportUtil.class.getName());
+
+  /** These postfixes are associated with Arc/Info ASCII Grid files
+   * TODO .0 habe ich auch schon gesehen. Nut leider kann man das nicht in einen enum packen.
+   * */
+	static public enum ARCASCII_POSTFIXES {
+		arc, dat, ascii, txt, asc, a00
+	};
+
+	/** These postfixes are associated with GeoTiff files */
+	static public enum GEOTIFF_POSTFIXES {
+		tif, tiff
+	};
+
+	/** These postfixes are associated with ESRI SHape files */
+	static public enum SHP_POSTFIXES {
+		shp, sbx, sbn, dbf, shx, 
+		qix, fix,	// Non-ESRI QuadTree Index stuff
+		cpg // Supported by ESRI. Contains the name of codepage used inside the DBF
+	};
+
+	/** These postfixes are associated with ordinary image files, excluding GeoTIFF endings please */
+	static public enum IMAGE_POSTFIXES {
+		png, gif, jpg, jpeg
+	};
+
+	/** These postfixes are associated with world files */
+	static public enum WORLD_POSTFIXES {
+		wld, jgw, pgw, tfw
+	};
+
+
+  /**
+   * Standard-CRS, welches verwendet wird, wenn beim Import kein CRS ermittelt
+   * werden kann (Default: {@link DefaultGeographicCRS#WGS84}).<br>
+   * <b>Achtung:</b><br>
+   * Anwendungen koennen diese Variable gefahrlos ueberschreiben, um ein fuer
+   * die Anwendung adaequates Standard-CRS zu verwenden.
+   */
+  public static CoordinateReferenceSystem DEFAULT_CRS = DefaultGeographicCRS.WGS84;
+
+  /**
+   * Diese Methode extrahiert saemtliche Features aus einem ShapeFile-Projekt
+   * (<code><i>name</i>.shp <i>name</i>.prj <i>name</i>.dbf ...</code>)
+   * und speichert diese in einer <code>org.geotools.feature.FeatureCollection</code>.<br>
+   *
+   * @param url {@link URL} to Shape-File
+   * @param prjUrl {@link URL} zu .prj Datei des Shape-File
+   *
+   *
+   * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
+   *
+   * @return {@link FeatureCollection} that was read
+   *
+   * @throws IOException
+   */
+  public static FeatureCollection readFeaturesFromShapeURL(URL url,
+			URL prjUrl) throws IOException {
+		ShapefileDataStore store = new ShapefileDataStore(url);
+		try {
+			// Testen, ob Projektion ermittelt werden kann, um vorab das
+			// Standard-CRS
+			// zu setzen
+			LOGGER.debug("  parseWKT on " + prjUrl);
+			CRS.parseWKT(readProjectionString(prjUrl));
+		} catch (Exception err) {
+			LOGGER.warn(" CRS.parseWKT mit Ex\n: ", err);
+			LOGGER.warn(" No projection found for file. Default is used.");
+			LOGGER
+					.warn(" NOT calling forceSchemaCRS now... please provide a URL to an existing .prj file!");
+			// store.forceSchemaCRS(DEFAULT_CRS);
+		}
+		String[] typeNames = store.getTypeNames();
+		FeatureCollection fc = store.getFeatureSource(typeNames[0])
+				.getFeatures();
+
+		// Create a new DefaultFeatureCollection to allow modifying
+	    // operations on the collection ("fc" is a DataFeatureCollection, whose
+	    // add(.) and remove(.) methods do nothing. Furthermore a FIDFeatureReader
+		// is used which returns copies of the features, so modifying the attributes
+		// does not effect the features in the collection!)
+	    FeatureCollection fc1 = FeatureCollections.newCollection( fc.getID() );
+	    fc1.addAll( fc );
+	    fc = fc1;
+
+	    return fc;
+	}
+
+
+  /**
+	 * Diese Methode extrahiert saemtliche Features aus einem ShapeFile-Projekt (<code><i>name</i>.shp <i>name</i>.prj <i>name</i>.dbf ...</code>)
+	 * und speichert diese in einer
+	 * <code>org.geotools.feature.FeatureCollection</code>.<br>
+	 *
+	 * @param file
+	 *            Shape-File
+	 * @throws java.lang.Exception
+	 *             bei irgendeinem Fehler
+	 *
+	 * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+	 *
+	 * TODO Wenn readFeaturesFromShapeURL getestet ist, dann sollte die hiet auf readFeaturesFromShapeURL(file.getURL) umgeleitet werden (SK)
+	 */
+  public static FeatureCollection readFeaturesFromShapeFile(File file) throws Exception {
+    ShapefileDataStore store   = new ShapefileDataStore(file.toURI().toURL());
+    File               prjFile = IOUtil.changeFileExt(file, "prj");
+    boolean            delPrjFile = false;
+    try {
+      // Testen, ob Projektion ermittelt werden kann, um vorab das Standard-CRS
+      // zu setzen
+      String prjString = readProjectionString(prjFile);
+      if ( prjString == null || prjString.trim().equals("") )
+        throw new FileNotFoundException("No proper prj-File exists: "+file.getName());
+      CRS.parseWKT(prjString);
+    } catch (FileNotFoundException err) {
+      store.forceSchemaCRS(getDEFAULT_CRS());
+      LOGGER.warn("No projection found for file "+file.getName()+". Default is used.");
+      delPrjFile = true; // von DataStore erzeugte Datei wieder loeschen
+    }
+    String[] typeNames = store.getTypeNames();
+    FeatureCollection fc = store.getFeatureSource(typeNames[0]).getFeatures();
+    if ( delPrjFile )
+      prjFile.delete();
+
+    // Create a new DefaultFeatureCollection to allow modifying
+    // operations on the collection ("fc" is a DataFeatureCollection, whose
+    // add(.) and remove(.) methods do nothing. Furthermore a FIDFeatureReader
+    // is used which returns copies of the features, so modifying the attributes
+    // does not effect the features in the collection!)
+    FeatureCollection fc1 = FeatureCollections.newCollection( fc.getID() );
+    fc1.addAll( fc );
+    fc = fc1;
+
+    return fc;
+  }
+
+
+  /**
+   * TODO DOKU
+   * @param shpURL
+   * @param prjURL
+   * @return
+   * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
+ * @throws IOException
+   */
+  public static DataStore readDataStoreFromShape(URL shpURL, URL prjURL) throws IOException {
+	  Map map = new HashMap();
+	  map.put( "url", shpURL );
+	  map.put( "create spatial index", true );
+
+	  //DataStore dataStore = DataStoreFinder.getDataStore( map );
+	  DataStore dataStore = new IndexedShapefileDataStore(shpURL, null, false, true, IndexedShapefileDataStore.TREE_QIX);
+	  // DataStore dataStore = new ShapefileDataStore(shpURL);
+	  System.out.println("DataStore = "+dataStore.getClass().toString());
+	  IndexedShapefileDataStore dataStoreIndex = (IndexedShapefileDataStore)dataStore;
+	  System.out.println("indexed = "+dataStoreIndex.isIndexed());
+	  System.out.println("memory = "+dataStoreIndex.isMemoryMapped());
+  	return dataStore;
+  }
+
+
+  /**
+   * Diese Methode extrahiert saemtliche Geometrien aus einem ShapeFile-Projekt
+   * (<code><i>name</i>.shp <i>name</i>.prj <i>name</i>.dbf ...</code>)
+   * und speichert diese in einer Liste (Vector) von {@link com.vividsolutions.jts.geom.Geometry}-Objekten.<br>
+   * Baut auf folgenden Geotools-Klassen auf:
+   * <code>
+   * <ul>
+   * <li>{@link ShapefileReader org.geotools.data.shapefile.shp.ShapefileReader}</li>
+   * <li>{@link Geometry        com.vividsolutions.jts.geom.Geometry}</li>
+   * </ul>
+   * </code>
+   * @param file Shape-File
+   * @throws java.lang.Exception bei irgendeinem Fehler
+   */
+  public static Vector<Geometry> readGeometriesFromShapeFile(File file) throws Exception {
+    FileChannel in = new FileInputStream(file).getChannel();
+    ShapefileReader r = new ShapefileReader( in, new Lock() );
+    Vector<Geometry> geomList = new Vector<Geometry>();
+    for(int i=1; r.hasNext(); i++) {
+        //        org.geotools.renderer.geom.Geometry shape = (org.geotools.renderer.geom.Geometry) r.nextRecord().shape();
+        //        org.geotools.geometry.Geometry shape = (org.geotools.geometry.Geometry) r.nextRecord().shape();
+        Object obj = r.nextRecord().shape();
+        Geometry shape = (Geometry)obj;
+        geomList.add(shape);
+      }
+      r.close();
+      return geomList;
+    }
+
+    /**
+     * Diese Methode importiert ein Raster aus einer Datei im ArcInfoASCII-Grid-Format.
+     * Das CRS wird aus einem prj-File (EPSG-Code "EPSG:..." oder WKT-Definition)
+     * gelesen. Ist dies nicht erfolgreich, wird {@link #DEFAULT_CRS}
+     * als CRS verwendet.
+     * @param file ASCII-File
+     * @throws java.lang.Exception bei irgendeinem Fehler
+     * @return {@link GridCoverage2D}
+     */
+    public static GridCoverage2D readGridFromArcInfoASCII(File file) throws Exception {
+      return readGridFromArcInfoASCII(file,null);
+    }
+
+    /**
+     * Diese Methode importiert ein Raster aus einer Datei im ArcInfoASCII-Grid-Format.
+     * Wenn kein CRS angegeben wird, wird versucht das CRS aus einem prj-File
+     * (EPSG-Code "EPSG:..." oder WKT-Definition) zu lesen. Ist dies nicht
+     * erfolgreich, wird {@link #DEFAULT_CRS} als CRS verwendet.
+     * @param file ASCII-File
+     * @param crs CoordinateReferenceSystem fuer das Raster (kann {@code null} sein)
+     * @throws java.lang.Exception bei irgendeinem Fehler
+     * TODO
+     */
+    public static GridCoverage2D readGridFromArcInfoASCII(File file, CoordinateReferenceSystem crs) throws Exception {
+    	return readGridFromArcInfoASCII(file.toURI().toURL(), crs);
+
+//      ArcGridRaster  reader = new ArcGridRaster( new BufferedReader( new InputStreamReader( new FileInputStream(file) ) ), false );
+//      WritableRaster raster = reader.readRaster();
+//      if (crs == null)
+//        crs = determineProjection(file);
+//
+////      System.out.println("Position  "+reader.getXlCorner()+" / "+reader.getYlCorner());
+////      System.out.println("Size      "+reader.getNCols()+" / "+reader.getNRows());
+////      System.out.println("Min/Max   "+reader.getMinValue()+" / "+reader.getMaxValue());
+////      System.out.println("NoData    "+reader.getNoData());
+////      System.out.println("CellSize  "+reader.getCellSize());
+//
+//      float x = (float) reader.getXlCorner(); // Suedwestliche Ecke!
+//      float y = (float) reader.getYlCorner(); // Suedwestliche Ecke!
+//      float w = (float) (reader.getNCols() * reader.getCellSize()); // reale Breite = RasterSpalten * Aufloesung
+//      float h = (float) (reader.getNRows() * reader.getCellSize()); // reale Hoehe = RasterZeilen * Aufloesung
+//      Envelope2D envelope = new Envelope2D(crs, new Rectangle2D.Float(x, y, w, h));
+//
+//      // WICHTIG: Name des Rasters sollte Leer-String sein, da ansonsten das
+//      //          Coloring des Rasters nicht klappt.
+//      //          --> Name der Categories muss (warum auch immer) mit dem Namen
+//      //              des Rasters uebereinstimmen!!!
+//      return new GridCoverageFactory().create("", raster, envelope);
+////
+////=== OHNE ArcGridRaster ===
+//////      ArcGridReader reader = new ArcGridReader( new BufferedReader( new InputStreamReader( new FileInputStream(file) ) ));
+////      ArcGridReader reader = new ArcGridReader( file );
+////      return (GridCoverage2D)reader.read(null);
+    }
+
+
+    /**
+     * Diese Methode importiert ein Raster aus einer Datei im ArcInfoASCII-Grid-Format.
+     * Wenn kein CRS angegeben wird, wird versucht das CRS aus einem prj-File
+     * (EPSG-Code "EPSG:..." oder WKT-Definition) zu lesen. Ist dies nicht
+     * erfolgreich, wird {@link #DEFAULT_CRS} als CRS verwendet.
+     * @param url Link to Arc/Info GRID ASCII file
+     * @param crs CoordinateReferenceSystem fuer das Raster (kann {@code null} sein)
+     * @throws java.lang.Exception bei irgendeinem Fehler
+     */
+    public static GridCoverage2D readGridFromArcInfoASCII(URL url, CoordinateReferenceSystem crs) throws Exception {
+      ArcGridRaster  reader = new ArcGridRaster( new BufferedReader( new InputStreamReader(url.openStream()) ), false );
+      WritableRaster raster = reader.readRaster();
+      if (crs == null)
+        crs = determineProjection( IOUtil.changeUrlExt(url,"prj"));
+
+//      System.out.println("Position  "+reader.getXlCorner()+" / "+reader.getYlCorner());
+//      System.out.println("Size      "+reader.getNCols()+" / "+reader.getNRows());
+//      System.out.println("Min/Max   "+reader.getMinValue()+" / "+reader.getMaxValue());
+//      System.out.println("NoData    "+reader.getNoData());
+//      System.out.println("CellSize  "+reader.getCellSize());
+
+      float x = (float) reader.getXlCorner(); // Suedwestliche Ecke!
+      float y = (float) reader.getYlCorner(); // Suedwestliche Ecke!
+      float w = (float) (reader.getNCols() * reader.getCellSize()); // reale Breite = RasterSpalten * Aufloesung
+      float h = (float) (reader.getNRows() * reader.getCellSize()); // reale Hoehe = RasterZeilen * Aufloesung
+      Envelope2D envelope = new Envelope2D(crs, new Rectangle2D.Float(x, y, w, h));
+
+      // WICHTIG: Name des Rasters sollte Leer-String sein, da ansonsten das
+      //          Coloring des Rasters nicht klappt.
+      //          --> Name der Categories muss (warum auch immer) mit dem Namen
+      //              des Rasters uebereinstimmen!!!
+      return new GridCoverageFactory().create("", raster, envelope);
+//
+//=== OHNE ArcGridRaster ===
+////      ArcGridReader reader = new ArcGridReader( new BufferedReader( new InputStreamReader( new FileInputStream(file) ) ));
+//      ArcGridReader reader = new ArcGridReader( file );
+//      return (GridCoverage2D)reader.read(null);
+    }
+
+
+
+
+
+    /**
+     * Diese Methode erzeugt einen {@link AbstractGridCoverage2DReader} aus einer
+     * Datei im GeoTIFF-Format.
+     * Zunaechst wird versucht, die Geo-Informationen (Referenz+CRS) aus den
+     * TIFF-Metadaten zu ermitteln. Ist dies nicht erfolgreich, werden
+     * ein gleichnamiges World-File (.tfw) und Projection-File (.prj)
+     * herangezogen (siehe {@link WorldImageReader}).
+     * @param file GeoTIFF-File
+     * @param crs erzwungenes CoordinateReferenceSystem fuer das Raster (kann {@code null} sein)
+     * @throws java.lang.Exception bei irgendeinem Fehler
+     * @deprecated {@link WorldImageReader} klappt noch nicht so 100%ig (Colorisierung schlaegt fehl!)
+     */
+    public static AbstractGridCoverage2DReader createGridReaderFromGeoTiff(File file, CoordinateReferenceSystem crs) throws Exception {
+      // Versuchen Geo-Information aus Tiff zu lesen
+      try {
+        Hints hints = new Hints(null);
+        // Wenn CRS angegeben, dieses durch Hint erzwingen
+        if ( crs != null )
+          hints.put( Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM, crs );
+        // Reader (mit Metadaten) erzeugen
+        GeoTiffReader reader = new GeoTiffReader(file,hints);
+        // Wenn kein Referenzsystem vorhanden, versuchen ein prj-File zu verwenden
+        if ( reader.getOriginalEnvelope().getCoordinateReferenceSystem() == null ) {
+          LOGGER.warn("No projection information found in '"+file.getName()+"'. Using prj-file...");
+          hints.put( Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM, determineProjection(file) );
+          reader = new GeoTiffReader(file,hints);
+        }
+        return reader;
+      } catch ( UnsupportedOperationException err )  {
+        // erwartet, wenn keine Geo-Information im Tiff vorhanden ist
+      } catch ( NullPointerException err ) {
+        // erwartet, wenn keine Geo-Information im Tiff vorhanden ist
+      }
+
+      // keine Geo-Informationen in Tiff
+      // --> Raster ueber ImageIO einlesen und WorldFile/ProjectionFile verwenden
+      LOGGER.warn("No geo information found in '" + file.getName() +  "'. Using world- and prj-file...");
+      // @todo check the work of WorldImageReader with colorization!
+      throw new UnsupportedOperationException("WorldImageReader does not work well, yet... AbstractGridCoverage2DReader can not be created from this Tiff!");
+//      Hints hints = new Hints(null);
+//      // Wenn CRS angegeben, dieses durch Hint erzwingen
+//      if ( crs != null )
+//        hints.put( Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM, crs );
+//      WorldImageReader reader = new WorldImageReader(file);
+//      return reader;
+    }
+
+    /**
+     * Diese Methode erzeugt einen {@link AbstractGridCoverage2DReader} aus einer
+     * Datei im GeoTIFF-Format.
+     * @param file GeoTIFF-File
+     * @throws java.lang.Exception bei irgendeinem Fehler
+     * @see #createGridReaderFromGeoTiff(File, CoordinateReferenceSystem)
+     * @deprecated {@link WorldImageReader} klappt noch nicht so 100%ig (Colorisierung schlaegt fehl!)
+     */
+    public static AbstractGridCoverage2DReader createGridReaderFromGeoTiff(File file) throws Exception {
+      return createGridReaderFromGeoTiff(file,null);
+    }
+
+    /**
+    * Diese Methode importiert ein Raster aus einer Datei im GeoTIFF-Format.
+    * @param file GeoTIFF-File
+    * @param crs erzwungenes CoordinateReferenceSystem fuer das Raster (kann {@code null} sein)
+    * @throws java.lang.Exception bei irgendeinem Fehler
+    * @see #createGridReaderFromGeoTiff(File, CoordinateReferenceSystem)
+    */
+   public static GridCoverage2D readGridFromGeoTiff(File file, CoordinateReferenceSystem crs) throws Exception {
+//     return (GridCoverage2D)createGridReaderFromGeoTiff(file, crs).read(null);
+     GridCoverage2D gc = null;
+     // Versuchen Geo-Information aus Tiff zu lesen
+     try {
+       Hints hints = new Hints(null);
+
+       // Wenn CRS angegeben, dieses durch Hint erzwingen
+       if ( crs != null )
+         hints.put( Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM, crs );
+       // Reader (mit Metadaten) erzeugen
+       GeoTiffReader reader = new GeoTiffReader(file,hints);
+       // Wenn kein Referenzsystem vorhanden, versuchen ein prj-File zu verwenden
+       if ( reader.getOriginalEnvelope().getCoordinateReferenceSystem() == null ) {
+         LOGGER.warn("No projection information found in '"+file.getName()+"'. Using prj-file...");
+         hints.put( Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM, determineProjection(file) );
+         reader = new GeoTiffReader(file,hints);
+       }
+       gc = (GridCoverage2D)reader.read(null);
+       return gc;
+     } catch ( UnsupportedOperationException err )  {
+    	 // erwartet, wenn keine Geo-Information im Tiff vorhanden ist
+//    	 ExceptionMonitor.show(null, err, "No geoinformation in TIFF, importing it as a normal file. Trying to read it as normal TIFF + Worldfile.");
+     } catch ( NullPointerException err ) {
+       // erwartet, wenn keine Geo-Information im Tiff vorhanden ist
+     }
+
+     // keine Geo-Informationen in Tiff
+     // --> Raster ueber ImageIO einlesen und WorldFile/ProjectionFile verwenden
+     LOGGER.warn("No geo information found in '" + file.getName() +
+                 "'. Using world- and prj-file...");
+     BufferedImage im = ImageIO.read(file);
+     if (im == null)
+       throw new IIOException("No image reader found for this image type!");
+     // World-File einlesen
+     File tfw = IOUtil.changeFileExt(file, "tfw");
+     double[] tfwInfo = readWorldFile(tfw);
+     float w = (float) (im.getWidth() * tfwInfo[0]); // reale Breite = RasterSpalten * hor. Aufloesung
+     float h = (float) (im.getHeight() * ( -tfwInfo[3])); // reale Hoehe = RasterZeilen * vert. Aufloesung
+     float x = (float) tfwInfo[4]; // Suedwestliche Ecke!
+     float y = (float) tfwInfo[5] - h; // Suedwestliche Ecke (im tfw-File steht die Nordwestliche!)
+     // ggf. Projektion einlesen
+     if (crs == null)
+       crs = determineProjection(file);
+     Envelope2D envelope = new Envelope2D(crs, new Rectangle2D.Float(x, y, w, h));
+     // WICHTIG: Name des Rasters sollte Leer-String sein, da ansonsten das
+     //          Coloring des Rasters nicht klappt.
+     //          --> Name der Categories muss (warum auch immer) mit dem Namen
+     //              des Rasters uebereinstimmen!!!
+     gc = new GridCoverageFactory().create("", im.copyData(null), envelope);
+     return gc;
+   }
+
+   /**
+    * Diese Methode importiert ein Raster aus einer Datei im GeoTIFF-Format.
+    * @param file GeoTIFF-File
+    * @throws java.lang.Exception bei irgendeinem Fehler
+    * @see #readGridFromGeoTiff(File, CoordinateReferenceSystem)
+    */
+   public static GridCoverage2D readGridFromGeoTiff(File file) throws Exception {
+     return readGridFromGeoTiff(file,null);
+   }
+
+   /**
+    * Diese Methode importiert ein Raster aus einer Datei im ArcInfoASCII-Grid-Format.
+    * Das CRS wird aus einem prj-File (EPSG-Code "EPSG:..." oder WKT-Definition)
+    * gelesen. Ist dies nicht erfolgreich, wird {@link #DEFAULT_CRS}
+    * als CRS verwendet.
+    * @param file ASCII-File
+    * @throws java.lang.Exception bei irgendeinem Fehler
+    */
+   public static WritableGridRaster readGridRasterFromArcInfoASCII(File file) throws Exception {
+     return readGridRasterFromArcInfoASCII(file,null);
+   }
+
+   /**
+    * Diese Methode importiert ein Raster aus einer Datei im ArcInfoASCII-Grid-Format.
+    * Wenn kein CRS angegeben wird, wird versucht das CRS aus einem prj-File
+    * (EPSG-Code "EPSG:..." oder WKT-Definition) zu lesen. Ist dies nicht
+    * erfolgreich, wird {@link #DEFAULT_CRS} als CRS verwendet.
+    * @param file ASCII-File
+    * @param crs CoordinateReferenceSystem fuer das Raster (kann {@code null} sein)
+    * @throws java.lang.Exception bei irgendeinem Fehler
+    */
+   public static WritableGridRaster readGridRasterFromArcInfoASCII(File file, CoordinateReferenceSystem crs) throws Exception {
+     ArcGridRaster  reader = new ArcGridRaster(new BufferedReader(new InputStreamReader(new FileInputStream(file))),false);
+     WritableRaster raster = reader.readRaster();
+     float x = (float)reader.getXlCorner(); // Suedwestliche Ecke!
+     float y = (float)reader.getYlCorner(); // Suedwestliche Ecke!
+     float w = (float)(reader.getNCols() * reader.getCellSize()); // reale Breite = RasterSpalten * Aufloesung
+     float h = (float)(reader.getNRows() * reader.getCellSize()); // reale Hoehe = RasterZeilen * Aufloesung
+     // Projektion einlesen
+     if (crs == null)
+       crs = determineProjection(file);
+     return new WritableGridRaster(raster, new Rectangle2D.Float(x,y,w,h), crs );
+
+//=== OHNE ArcGridRaster ===
+//     GridCoverage2D grid   = readGridFromArcInfoASCII(null,input);
+//     WritableRaster raster = grid.getRenderedImage().copyData(null);
+//     return( new WritableGridRaster(raster,grid.getEnvelope2D()) );
+   }
+
+   /**
+    * Diese Methode importiert ein Raster aus einer Datei im GeoTIFF-Format.
+    * Zunaechst wird versucht, die Geo-Informationen (Referenz+CRS) aus den
+    * TIFF-Metadaten zu ermitteln. Ist dies nicht erfolgreich, werden
+    * ein gleichnamiges World-File (.tfw) und Projection-File (.prj)
+    * herangezogen. Als Projektion (.prj) ist sowohl ein EPSG-Code "EPSG:...",
+    * als auch eine WKT-Definition erlaubt. Kann kein CRS ermitteln werden,
+    * wird {@link #DEFAULT_CRS} als CRS verwendet.
+    * @param file GeoTIFF-File
+    * @throws java.lang.Exception bei irgendeinem Fehler
+     */
+   public static WritableGridRaster readGridRasterFromGeoTiff(File file) throws Exception {
+     return readGridRasterFromGeoTiff(file,null);
+   }
+
+   /**
+    * Diese Methode importiert ein Raster aus einer Datei im GeoTIFF-Format.
+    * Zunaechst wird versucht, die Geo-Informationen (Referenz+CRS) aus den
+    * TIFF-Metadaten zu ermitteln. Ist dies nicht erfolgreich, werden
+    * ein gleichnamiges World-File (.tfw) und Projection-File (.prj)
+    * herangezogen. Als Projektion (.prj) ist sowohl ein EPSG-Code "EPSG:...",
+    * als auch eine WKT-Definition erlaubt. Kann kein CRS ermitteln werden,
+    * wird {@link #DEFAULT_CRS} als CRS verwendet.
+    * @param file GeoTIFF-File
+    * @param crs erzwungenes CoordinateReferenceSystem fuer das Raster (kann {@code null} sein)
+    * @throws java.lang.Exception bei irgendeinem Fehler
+    */
+  public static WritableGridRaster readGridRasterFromGeoTiff(File file, CoordinateReferenceSystem crs) throws Exception {
+//    // GeoTiff-File einlesen
+//    BufferedImage im = ImageIO.read( file );
+//    if ( im == null )
+//      throw new IIOException("No image reader found for this image type!");
+//    // World-File einlesen
+//    File tfw = IOUtil.changeFileExt(file,"tfw");
+//    double[] tfwInfo = readWorldFile(tfw);
+//    // ggf. Projektion einlesen
+//    if (crs == null)
+//      crs = determineProjection(file);
+//
+//    float w = (float) (im.getWidth() * tfwInfo[0]); // reale Breite = RasterSpalten * hor. Aufloesung
+//    float h = (float) (im.getHeight() * (-tfwInfo[3])); // reale Hoehe = RasterZeilen * vert. Aufloesung
+//    float x = (float) tfwInfo[4]; // Suedwestliche Ecke!
+//    float y = (float) tfwInfo[5] - h ; // Suedwestliche Ecke (im tfw-File steht die Nordwestliche!)
+//
+//    Rectangle2D        env    = new Rectangle2D.Float(x,y,w,h);
+//    WritableGridRaster raster = new WritableGridRaster(
+//      im.getData().getDataBuffer().getDataType(),
+//      0,
+//      0,
+//      im.getWidth(),
+//      im.getHeight(),
+//      env,
+//      crs
+//    );
+//
+
+    GridCoverage2D gc  = readGridFromGeoTiff(file,crs);
+    Rectangle2D    env = gc.getEnvelope2D();
+    RenderedImage  im  = gc.getRenderedImage();
+    WritableGridRaster raster = new WritableGridRaster(
+      im.getData().getDataBuffer().getDataType(),
+      0,
+      0,
+      im.getWidth(),
+      im.getHeight(),
+      env,
+      crs
+    );
+
+    im.copyData(raster);
+
+    return raster;
+  }
+
+  /**
+   * Liest ein World-File (.tfw) ein und liefert die darin zeilenweise
+   * gespeicherten Werte zurueck. Leer- und Kommentarzeilen werden dabei
+   * ignoriert. Kann ein Zeilen-Wert nicht in einen <code>double</code>
+   * umgewandelt werden, wird diese Zeile ignoriert, als 1.0 interpretiert
+   * und eine Meldung in die Standard-Fehler-Ausgabe geschrieben.<br>
+   * Der zurueckgegebene Array hat mindestens die Groesse 6:<br>
+   * <ol>
+   *    <li>Zellengroesse in X-Richtung (in Meter)</li>
+   *   <li>Koeffizient fuer Rotation in Y-Richtung</li>
+   *   <li>Koeffizient fuer Rotation in X-Richtung</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>
+   * @todo WorldFile-Spec vervollstaendigen
+   * @param file World-File
+   * @exception IOException falls die Datei nicht existiert oder ein unerwarteter
+   *            Fehler beim Einlesen auftritt
+   * @see IOUtil#isCommentLine(String)
+   * @see System#err
+   */
+
+   public static double[] readWorldFile(File file) throws IOException {
+     return readWorldFile(  new FileInputStream(file) ) ;
+   }
+
+
+   /**
+    * Liest ein World-File (.tfw) ein und liefert die darin zeilenweise
+    * gespeicherten Werte zurueck. Leer- und Kommentarzeilen werden dabei
+    * ignoriert. Kann ein Zeilen-Wert nicht in einen <code>double</code>
+    * umgewandelt werden, wird diese Zeile ignoriert, als 1.0 interpretiert
+    * und eine Meldung in die Standard-Fehler-Ausgabe geschrieben.<br>
+    * Der zurueckgegebene Array hat mindestens die Groesse 6:<br>
+    * <ol>
+    *    <li>Zellengroesse in X-Richtung (in Meter)</li>
+    *   <li>Koeffizient fuer Rotation in Y-Richtung</li>
+    *   <li>Koeffizient fuer Rotation in X-Richtung</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>
+    * @todo WorldFile-Spec vervollstaendigen
+    *
+    * @param inputStream Stream of World-File
+    * @exception IOException falls die Datei nicht existiert oder ein unerwarteter
+    *            Fehler beim Einlesen auftritt
+    * @see IOUtil#isCommentLine(String)
+    * @see System#err
+    *
+    * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+    * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
+    */
+   public static double[] readWorldFile(InputStream inputStream) throws IOException {
+	   Vector<Double> tfwValues = new Vector<Double>();
+	   BufferedReader in = new BufferedReader( new InputStreamReader( inputStream ) );
+	   String line = null;
+	   for(int lineNo=1; in.ready() && (line=in.readLine().trim()) != null; lineNo++ ) {
+		   if ( IOUtil.isCommentLine(line) || line.equals("") )
+			   continue;
+		   try {
+			   StringTokenizer st = new StringTokenizer(line);
+			   tfwValues.add( Double.parseDouble( st.nextToken(" \n;,#|/") ) );
+		   } catch (Exception err) {
+			   System.err.println("WorldFile-Error in line "+lineNo+": "+err);
+
+//		(SK)   System.err.println("WorldFile-Error in '"+file.getAbsolutePath()+"' (line "+lineNo+"): "+err);
+			   System.err.println("   >> expected value is set to 1.0");
+			   tfwValues.add( 1.0 );
+		   }
+	   }
+
+	   while ( tfwValues.size() < 6 ) {
+		   System.err.println("WorldFile-Error: value "+tfwValues.size()+" missing!");
+//		(SK)   System.err.println("WorldFile-Error in '"+file.getAbsolutePath()+"': value "+tfwValues.size()+" missing!");
+		   System.err.println("   >> expected value is set to 1.0");
+		   tfwValues.add( 1.0 );
+	   }
+
+	   // Vector in Array umwandeln
+	   double[] ret = new double[tfwValues.size()];
+	   for (int i=0; i<ret.length; i++)
+		   ret[i] = tfwValues.elementAt(i);
+	   return ret;
+   }
+
+   /**
+    * Liest das CRS aus einer Datei. Zunaechst wird versucht das CRS aus der
+    * uebergebene Datei zu lesen. Ist dies nicht erfolgreich wird das zur
+    * Datei korrespondierende prj-File herangezogen.
+    * @param file Datei
+    * @return {@code null}, wenn kein CRS gelesen werden konnte
+    */
+   public static CoordinateReferenceSystem determineProjection(File file) throws IOException {
+
+	//****************************************************************************
+	// schonmal teilweise migriert... das geht direkt an die URL methode weiter...
+	//****************************************************************************
+
+//     CoordinateReferenceSystem crs = null;
+//     // Versuchen CRS aus angegebener Datei zu lesen
+//     crs = readProjectionFile(file);
+//     // Wenn nicht erfolgreich versuchen die zur Datei korrespondierende
+//     // prj-Datei einzulesen
+//     if ( crs == null )
+//       crs = readProjectionFile( IOUtil.changeFileExt(file,"prj") );
+//     // Wenn nicht erfolgreich, Default verwenden
+//     if ( crs == null ) {
+//       LOGGER.warn("No projection found for file '"+file.getName()+"'. Default CRS used.");
+//       crs = DEFAULT_CRS;
+//     }
+     return determineProjection(file.toURI().toURL());
+   }
+
+
+	/**
+	 * Liest das CRS aus einer URL. Wenn keine CRS gelesen werden kann, dann
+	 * wird die Endung der URL gegen .prj gewechselt und nochmal versucht bevor
+	 * das {@link #DEFAULT_CRS} benutzt wird.
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public static CoordinateReferenceSystem determineProjection(URL prjUrl) {
+		CoordinateReferenceSystem crs = null;
+		// Versuchen CRS aus angegebener Datei zu lesen
+
+		LOGGER.debug("determineProjection: Try to read a projection from URL "
+				+ prjUrl);
+		try {
+			crs = GeoImportUtil.readProjectionFile(prjUrl);
+		} catch (IOException e) {
+		}
+
+		if (crs == null) {
+			try {
+				crs = GeoImportUtil.readProjectionFile(IOUtil.changeUrlExt(
+						prjUrl, "prj"));
+			} catch (IllegalArgumentException e) {
+			} catch (IOException e) {
+			}
+		}
+
+		// Wenn nicht erfolgreich, Default verwenden
+		if (crs == null) {
+			LOGGER.warn("No projection found in URL. Default CRS used.");
+			crs = getDEFAULT_CRS();
+		}
+		return crs;
+	}
+
+
+   /**
+    * Liest ein CRS aus einer URL. Als Dateiinhalt wird entweder ein
+    * EPSG-Code oder eine WKT-Definition des CRS akzeptiert.
+    * @param prjURL prj-Datei in der die Projektion hinterlegt ist
+    * @return {@code null}, wenn kein CRS gelesen werden konnte
+    * @see GTUtil#createCRS(String)
+    *
+    * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+    * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
+    * @throws IOException falls die URL nicht wie erwartet gelesen werden konnte.
+    */
+   public static CoordinateReferenceSystem readProjectionFile(URL prjURL) throws IOException {
+	   String crsDefinition = readProjectionString(prjURL);
+	   CoordinateReferenceSystem crs = GTUtil.createCRS( crsDefinition );
+	   return crs;
+   }
+
+   /**
+    * Liest ein CRS aus einer Datei. Als Dateiinhalt wird entweder ein
+    * EPSG-Code oder eine WKT-Definition des CRS akzeptiert.
+    * @param prjFile prj-Datei in der die Projektion hinterlegt ist
+    * @return {@code null}, wenn kein CRS gelesen werden konnte
+    * @see GTUtil#createCRS(String)
+    *
+    * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+    */
+   public static CoordinateReferenceSystem readProjectionFile(File prjFile) throws IOException {
+     String crsDefinition = readProjectionString(prjFile);
+     CoordinateReferenceSystem crs = GTUtil.createCRS( crsDefinition );
+//     if ( crs == null )
+//       LOGGER.warn("CRS can not be read from file '"+(prjFile == null ? "null" : prjFile.getName())+"'");
+     return crs;
+   }
+
+   /**
+    * Liest die ersten Zeilen der angegebenen prj-Datei und fuegt sie zu einem
+    * String zusammen. Wenn die Datei zu gross ist, wird ein Leerstring zurueckgegeben,
+    * da es sich dann nicht um eine Projektionsdefinition handelt.
+    * @param prjFile prj-Datei
+    * @return Leerstring, falls die Datei nicht existiert oder groesser als 10KB ist
+    *
+    * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+    */
+   private static String readProjectionString(File prjFile) throws IOException {
+     // Wenn Datei groesser als 10KB, dann ist es kein prj-File
+     if ( !prjFile.exists() || !prjFile.isFile() ||
+          prjFile.length() == 0 || prjFile.length() > 10240 )
+       return "";
+
+     // Alle Zeilen der Datei aneinander haengen
+     BufferedReader input = new BufferedReader( new InputStreamReader( new FileInputStream(prjFile) ) );
+     StringBuffer buffer = new StringBuffer();
+     String line = null;
+     while( input.ready() && (line = input.readLine()) != null )
+       if ( !IOUtil.isCommentLine(line) )
+         buffer.append(" ").append(line);
+     input.close();
+     return buffer.toString().trim();
+
+   }
+
+   /**
+    * Liest alle Zeilen aus der prj-Datei URL und fuegt diese zu einem
+    * String zusammen
+    *
+    * Kommentarzeilen werden ignoriert.
+    *
+    * Wenn mehr als 3000 Zeichen (ohne Kommentare) gelesen werden, wird davon
+    * ausgegangen, dass es sich nicht um eine .PRJ Datei handelt, und "" wird
+    * zurückgegeben.
+    *
+    * @param url {@link URL} auf prj-Datei
+    *
+    * @return Leerstring, wenn url == null
+    *
+    * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
+    */
+   public static String readProjectionString(URL url) throws IOException {
+     if (url == null) {
+       LOGGER.debug("readProjectionString returned empty String for url==null");
+       return "";
+     }
+
+     BufferedReader input = new BufferedReader(new InputStreamReader(url.openStream()));
+     try {
+         // Alle Zeilen der Datei aneinander haengen
+         StringBuffer buffer = new StringBuffer();
+         String line = null;
+         while (input.ready() && (line = input.readLine()) != null) {
+           if (!IOUtil.isCommentLine(line))
+             buffer.append(" ").append(line);
+           if (buffer.length() > 3000) {
+//             LOGGER.warn("The URL " + url + " doesn't seem point to a .prj file, because size is > 3000 characters. Returning \"\"");
+             return "";
+           }
+         }
+         final String prjString = buffer.toString().trim();
+         // LOGGER.debug("This is the PRJ String from URL = \n"+prjString);
+         return prjString;
+       } finally {
+         input.close();
+       }
+     }
+
+
+public static void setDEFAULT_CRS(CoordinateReferenceSystem dEFAULT_CRS) {
+	DEFAULT_CRS = dEFAULT_CRS;
+}
+
+
+public static CoordinateReferenceSystem getDEFAULT_CRS() {
+	return DEFAULT_CRS;
+}
+
+   }

Modified: trunk/src/schmitzm/geotools/map/event/FeatureModifiedEvent.java
===================================================================
--- trunk/src/schmitzm/geotools/map/event/FeatureModifiedEvent.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/map/event/FeatureModifiedEvent.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,48 +1,66 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.map.event;
-
-import org.geotools.feature.Feature;
-import org.geotools.map.MapLayer;
-
-import schmitzm.geotools.gui.JEditorPane;
-
-/**
- * Diese Klasse stellt ein Ereignis dar, das ein {@link JEditorPane} ausloest,
- * wenn der Anwender Features in der Karte veraendert.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class FeatureModifiedEvent extends JEditorPaneEvent {
-  /** Feature das veraendert wurde. */
-  protected Feature feature = null;
-
-  /**
-   * Erzeugt ein neues Ereignis.
-   * @param sourceMap      Karte in der die Veraenderung vorgenommen wurde
-   * @param sourceLayer    Layer aus dem die Features stammen
-   * @param feature        veraendertes Features
-   * @param sourceObject   Objekt, das die Aenderung initiiert hat (wenn {@code null},
-   *                       wird das MapPane als Ausloeser gesetzt)
-   */
-  public FeatureModifiedEvent(JEditorPane sourceMap, MapLayer sourceLayer, Feature feature, Object sourceObject) {
-    super(sourceMap, sourceLayer, sourceObject);
-    this.feature = feature;
-  }
-
-  /**
-   * Liefert das veraenderte Feature.
-   */
-  public Feature getModifiedFeature() {
-    return feature;
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.map.event;
+
+import org.geotools.feature.Feature;
+import org.geotools.map.MapLayer;
+
+import schmitzm.geotools.gui.JEditorPane;
+
+/**
+ * Diese Klasse stellt ein Ereignis dar, das ein {@link JEditorPane} ausloest,
+ * wenn der Anwender Features in der Karte veraendert.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class FeatureModifiedEvent extends JEditorPaneEvent {
+  /** Feature das veraendert wurde. */
+  protected Feature feature = null;
+
+  /**
+   * Erzeugt ein neues Ereignis.
+   * @param sourceMap      Karte in der die Veraenderung vorgenommen wurde
+   * @param sourceLayer    Layer aus dem die Features stammen
+   * @param feature        veraendertes Features
+   * @param sourceObject   Objekt, das die Aenderung initiiert hat (wenn {@code null},
+   *                       wird das MapPane als Ausloeser gesetzt)
+   */
+  public FeatureModifiedEvent(JEditorPane sourceMap, MapLayer sourceLayer, Feature feature, Object sourceObject) {
+    super(sourceMap, sourceLayer, sourceObject);
+    this.feature = feature;
+  }
+
+  /**
+   * Liefert das veraenderte Feature.
+   */
+  public Feature getModifiedFeature() {
+    return feature;
+  }
+}

Modified: trunk/src/schmitzm/geotools/map/event/FeatureSelectedEvent.java
===================================================================
--- trunk/src/schmitzm/geotools/map/event/FeatureSelectedEvent.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/map/event/FeatureSelectedEvent.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,59 +1,77 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.map.event;
-
-import org.geotools.feature.FeatureCollection;
-import org.geotools.map.MapLayer;
-
-import schmitzm.geotools.gui.JMapPane;
-
-import com.vividsolutions.jts.geom.Envelope;
-
-/**
- * Diese Klasse stellt ein Ereignis dar, das ein {@link JMapPane} ausloest,
- * wenn der Anwender Features in der Karte ausgewaehlt hat.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class FeatureSelectedEvent extends ObjectSelectionEvent<FeatureCollection> {
-  /**
-   * Erzeugt ein neues Ereignis.
-   * @param sourceMap      Karte in der die Selektion vorgenommen wurde
-   * @param sourceLayer    Layer aus dem die Features stammen
-   * @param envelope       Bereich der selektiert wurde
-   * @param result         selektierte Features
-   * @param sourceObject   Objekt, das die Selektion initiiert hat (wenn {@code null},
-   *                       wird das MapPane als Ausloeser gesetzt)
-   */
-  public FeatureSelectedEvent(JMapPane sourceMap, MapLayer sourceLayer, Envelope envelope, FeatureCollection result, Object sourceObject) {
-    super(sourceMap, sourceLayer, envelope, result, sourceObject);
-  }
-
-  /**
-   * Erzeugt ein neues Ereignis.
-   * @param sourceMap      Karte in der die Selektion vorgenommen wurde
-   * @param sourceLayer    Layer aus dem die Features stammen
-   * @param envelope       Bereich der selektiert wurde
-   * @param result         selektierte Features
-   */
-  public FeatureSelectedEvent(JMapPane sourceMap, MapLayer sourceLayer, Envelope envelope, FeatureCollection result) {
-    this(sourceMap, sourceLayer, envelope, result,null);
-  }
-
-//  /**
-//   * Liefert die selektierten Features.
-//   */
-//  public FeatureCollection getSelectionResult() {
-//    return result;
-//  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.map.event;
+
+import org.geotools.feature.FeatureCollection;
+import org.geotools.map.MapLayer;
+
+import schmitzm.geotools.gui.JMapPane;
+
+import com.vividsolutions.jts.geom.Envelope;
+
+/**
+ * Diese Klasse stellt ein Ereignis dar, das ein {@link JMapPane} ausloest,
+ * wenn der Anwender Features in der Karte ausgewaehlt hat.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class FeatureSelectedEvent extends ObjectSelectionEvent<FeatureCollection> {
+  /**
+   * Erzeugt ein neues Ereignis.
+   * @param sourceMap      Karte in der die Selektion vorgenommen wurde
+   * @param sourceLayer    Layer aus dem die Features stammen
+   * @param envelope       Bereich der selektiert wurde
+   * @param result         selektierte Features
+   * @param sourceObject   Objekt, das die Selektion initiiert hat (wenn {@code null},
+   *                       wird das MapPane als Ausloeser gesetzt)
+   */
+  public FeatureSelectedEvent(JMapPane sourceMap, MapLayer sourceLayer, Envelope envelope, FeatureCollection result, Object sourceObject) {
+    super(sourceMap, sourceLayer, envelope, result, sourceObject);
+  }
+
+  /**
+   * Erzeugt ein neues Ereignis.
+   * @param sourceMap      Karte in der die Selektion vorgenommen wurde
+   * @param sourceLayer    Layer aus dem die Features stammen
+   * @param envelope       Bereich der selektiert wurde
+   * @param result         selektierte Features
+   */
+  public FeatureSelectedEvent(JMapPane sourceMap, MapLayer sourceLayer, Envelope envelope, FeatureCollection result) {
+    this(sourceMap, sourceLayer, envelope, result,null);
+  }
+
+//  /**
+//   * Liefert die selektierten Features.
+//   */
+//  public FeatureCollection getSelectionResult() {
+//    return result;
+//  }
+
+}

Modified: trunk/src/schmitzm/geotools/map/event/GeneralSelectionEvent.java
===================================================================
--- trunk/src/schmitzm/geotools/map/event/GeneralSelectionEvent.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/map/event/GeneralSelectionEvent.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,57 +1,75 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.map.event;
-
-import schmitzm.geotools.gui.JMapPane;
-
-import com.vividsolutions.jts.geom.Envelope;
-
-/**
- * Diese Klasse stellt ein Ereignis dar, das ein {@link JMapPane} ausloest,
- * wenn der Anwender (irgendeinen) einen Bereich in der Karte ausgewaehlt hat,
- * auch wenn dort keine Objekte selektiert wurden.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class GeneralSelectionEvent extends JMapPaneEvent {
-  /** Bereich der selektiert wurde. */
-  protected Envelope envelope    = null;
-
-  /**
-   * Erzeugt ein neues Ereignis.
-   * @param source Karte in der die Selektion vorgenommen wurde
-   * @param envelope  Bereich der selektiert wurde
-   * @param sourceObject Objekt, das die Selektion initiiert hat (wenn {@code null},
-   *                     wird das MapPane als Ausloeser gesetzt)
-   */
-  public GeneralSelectionEvent(JMapPane source, Envelope envelope, Object sourceObject) {
-    super(source, sourceObject);
-    this.envelope = envelope;
-  }
-
-  /**
-   * Erzeugt ein neues Ereignis.
-   * @param sourceMap Karte in der die Selektion vorgenommen wurde
-   * @param envelope  Bereich der selektiert wurde
-   */
-  public GeneralSelectionEvent(JMapPane sourceMap, Envelope envelope) {
-    this(sourceMap,envelope,null);
-  }
-
-
-  /**
-   * Liefert den Bereich ueber den selektiert wurde.
-   */
-  public Envelope getSelectionRange() {
-    return envelope;
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.map.event;
+
+import schmitzm.geotools.gui.JMapPane;
+
+import com.vividsolutions.jts.geom.Envelope;
+
+/**
+ * Diese Klasse stellt ein Ereignis dar, das ein {@link JMapPane} ausloest,
+ * wenn der Anwender (irgendeinen) einen Bereich in der Karte ausgewaehlt hat,
+ * auch wenn dort keine Objekte selektiert wurden.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class GeneralSelectionEvent extends JMapPaneEvent {
+  /** Bereich der selektiert wurde. */
+  protected Envelope envelope    = null;
+
+  /**
+   * Erzeugt ein neues Ereignis.
+   * @param source Karte in der die Selektion vorgenommen wurde
+   * @param envelope  Bereich der selektiert wurde
+   * @param sourceObject Objekt, das die Selektion initiiert hat (wenn {@code null},
+   *                     wird das MapPane als Ausloeser gesetzt)
+   */
+  public GeneralSelectionEvent(JMapPane source, Envelope envelope, Object sourceObject) {
+    super(source, sourceObject);
+    this.envelope = envelope;
+  }
+
+  /**
+   * Erzeugt ein neues Ereignis.
+   * @param sourceMap Karte in der die Selektion vorgenommen wurde
+   * @param envelope  Bereich der selektiert wurde
+   */
+  public GeneralSelectionEvent(JMapPane sourceMap, Envelope envelope) {
+    this(sourceMap,envelope,null);
+  }
+
+
+  /**
+   * Liefert den Bereich ueber den selektiert wurde.
+   */
+  public Envelope getSelectionRange() {
+    return envelope;
+  }
+}

Modified: trunk/src/schmitzm/geotools/map/event/GridCoverageSelectedEvent.java
===================================================================
--- trunk/src/schmitzm/geotools/map/event/GridCoverageSelectedEvent.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/map/event/GridCoverageSelectedEvent.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,60 +1,78 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.map.event;
-
-import org.geotools.coverage.grid.GridCoverage2D;
-import org.geotools.map.MapLayer;
-
-import schmitzm.geotools.gui.JMapPane;
-
-import com.vividsolutions.jts.geom.Envelope;
-
-/**
- * Diese Klasse stellt ein Ereignis dar, das ein {@link JMapPane} ausloest,
- * wenn der Anwender ein Raster in der Karte ausgewaehlt hat.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class GridCoverageSelectedEvent extends ObjectSelectionEvent<GridCoverage2D> {
-
-  /**
-   * Erzeugt ein neues Ereignis.
-   * @param sourceMap      Karte in der die Selektion vorgenommen wurde
-   * @param sourceLayer    Layer aus dem die Features stammen
-   * @param envelope       Bereich der selektiert wurde
-   * @param result         selektierters Teil-Raster
-   * @param sourceObject   Objekt, das die Selektion initiiert hat (wenn {@code null},
-   *                       wird das MapPane als Ausloeser gesetzt)
-   */
-  public GridCoverageSelectedEvent(JMapPane sourceMap, MapLayer sourceLayer, Envelope envelope, GridCoverage2D result, Object sourceObject) {
-    super(sourceMap,sourceLayer,envelope,result,sourceObject);
-  }
-
-  /**
-   * Erzeugt ein neues Ereignis.
-   * @param sourceMap      Karte in der die Selektion vorgenommen wurde
-   * @param sourceLayer    Layer aus dem die Features stammen
-   * @param envelope       Bereich der selektiert wurde
-   * @param result         selektierters Teil-Raster
-   */
-  public GridCoverageSelectedEvent(JMapPane sourceMap, MapLayer sourceLayer, Envelope envelope, GridCoverage2D result) {
-    this(sourceMap,sourceLayer,envelope,result,null);
-  }
-
-//  /**
-//   * Liefert das selektierte Teil-Raster.
-//   */
-//  public GridCoverage2D getSelectionResult() {
-//    return result;
-//  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.map.event;
+
+import org.geotools.coverage.grid.GridCoverage2D;
+import org.geotools.map.MapLayer;
+
+import schmitzm.geotools.gui.JMapPane;
+
+import com.vividsolutions.jts.geom.Envelope;
+
+/**
+ * Diese Klasse stellt ein Ereignis dar, das ein {@link JMapPane} ausloest,
+ * wenn der Anwender ein Raster in der Karte ausgewaehlt hat.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class GridCoverageSelectedEvent extends ObjectSelectionEvent<GridCoverage2D> {
+
+  /**
+   * Erzeugt ein neues Ereignis.
+   * @param sourceMap      Karte in der die Selektion vorgenommen wurde
+   * @param sourceLayer    Layer aus dem die Features stammen
+   * @param envelope       Bereich der selektiert wurde
+   * @param result         selektierters Teil-Raster
+   * @param sourceObject   Objekt, das die Selektion initiiert hat (wenn {@code null},
+   *                       wird das MapPane als Ausloeser gesetzt)
+   */
+  public GridCoverageSelectedEvent(JMapPane sourceMap, MapLayer sourceLayer, Envelope envelope, GridCoverage2D result, Object sourceObject) {
+    super(sourceMap,sourceLayer,envelope,result,sourceObject);
+  }
+
+  /**
+   * Erzeugt ein neues Ereignis.
+   * @param sourceMap      Karte in der die Selektion vorgenommen wurde
+   * @param sourceLayer    Layer aus dem die Features stammen
+   * @param envelope       Bereich der selektiert wurde
+   * @param result         selektierters Teil-Raster
+   */
+  public GridCoverageSelectedEvent(JMapPane sourceMap, MapLayer sourceLayer, Envelope envelope, GridCoverage2D result) {
+    this(sourceMap,sourceLayer,envelope,result,null);
+  }
+
+//  /**
+//   * Liefert das selektierte Teil-Raster.
+//   */
+//  public GridCoverage2D getSelectionResult() {
+//    return result;
+//  }
+
+}

Modified: trunk/src/schmitzm/geotools/map/event/GridCoverageValueSelectedEvent.java
===================================================================
--- trunk/src/schmitzm/geotools/map/event/GridCoverageValueSelectedEvent.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/map/event/GridCoverageValueSelectedEvent.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,76 +1,94 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.map.event;
-
-import java.awt.geom.Point2D;
-
-import org.geotools.map.MapLayer;
-
-import schmitzm.geotools.gui.JMapPane;
-
-import com.vividsolutions.jts.geom.Envelope;
-
-/**
- * Diese Klasse stellt ein Ereignis dar, das ein {@link JMapPane} ausloest,
- * wenn der Anwender den Wert eines Rasters in der Karte ausgewaehlt hat.
- *
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- *
- * @version 1.0
- *
- *
- * Da Raster auch mehrere Baender haben kann, habe ich von ObjectSelectionEvent
- * Double auf ObjectSelectionEvent double[] geaendert. Die laenge des double array
- * entspricht der Anzahl der Baender.
- *
- * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
- *
- * @version 1.1
- *
- */
-public class GridCoverageValueSelectedEvent extends ObjectSelectionEvent<double[]> {
-  /** Punkt auf den geklickt wurde */
-  private Point2D point = null;
-
-  /**
-   * Erzeugt ein neues Ereignis.
-   * @param sourceMap      Karte in der die Selektion vorgenommen wurde
-   * @param sourceLayer    Layer aus dem die Features stammen
-   * @param point          Punkt der selektiert wurde
-   * @param result         selektierters Teil-Raster
-   * @param sourceObject   Objekt, das die Selektion initiiert hat (wenn {@code null},
-   *                       wird das MapPane als Ausloeser gesetzt)
-   */
-  public GridCoverageValueSelectedEvent(JMapPane sourceMap, MapLayer sourceLayer, Point2D point, double[] result, Object sourceObject) {
-    super(sourceMap,sourceLayer,new Envelope(point.getX(),point.getX(),point.getY(),point.getY()),result, sourceObject);
-    this.point = point;
-  }
-
-  /**
-   * Erzeugt ein neues Ereignis.
-   * @param sourceMap      Karte in der die Selektion vorgenommen wurde
-   * @param sourceLayer    Layer aus dem die Features stammen
-   * @param point          Punkt der selektiert wurde
-   * @param result         selektierters Teil-Raster
-   */
-  public GridCoverageValueSelectedEvent(JMapPane sourceMap, MapLayer sourceLayer, Point2D point, double[] result) {
-    this(sourceMap,sourceLayer,point,result,null);
-  }
-
-  /**
-   * Liefert den selektierten Punkt.
-   */
-  public Point2D getSelectionPoint() {
-    return point;
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.map.event;
+
+import java.awt.geom.Point2D;
+
+import org.geotools.map.MapLayer;
+
+import schmitzm.geotools.gui.JMapPane;
+
+import com.vividsolutions.jts.geom.Envelope;
+
+/**
+ * Diese Klasse stellt ein Ereignis dar, das ein {@link JMapPane} ausloest,
+ * wenn der Anwender den Wert eines Rasters in der Karte ausgewaehlt hat.
+ *
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ *
+ * @version 1.0
+ *
+ *
+ * Da Raster auch mehrere Baender haben kann, habe ich von ObjectSelectionEvent
+ * Double auf ObjectSelectionEvent double[] geaendert. Die laenge des double array
+ * entspricht der Anzahl der Baender.
+ *
+ * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
+ *
+ * @version 1.1
+ *
+ */
+public class GridCoverageValueSelectedEvent extends ObjectSelectionEvent<double[]> {
+  /** Punkt auf den geklickt wurde */
+  private Point2D point = null;
+
+  /**
+   * Erzeugt ein neues Ereignis.
+   * @param sourceMap      Karte in der die Selektion vorgenommen wurde
+   * @param sourceLayer    Layer aus dem die Features stammen
+   * @param point          Punkt der selektiert wurde
+   * @param result         selektierters Teil-Raster
+   * @param sourceObject   Objekt, das die Selektion initiiert hat (wenn {@code null},
+   *                       wird das MapPane als Ausloeser gesetzt)
+   */
+  public GridCoverageValueSelectedEvent(JMapPane sourceMap, MapLayer sourceLayer, Point2D point, double[] result, Object sourceObject) {
+    super(sourceMap,sourceLayer,new Envelope(point.getX(),point.getX(),point.getY(),point.getY()),result, sourceObject);
+    this.point = point;
+  }
+
+  /**
+   * Erzeugt ein neues Ereignis.
+   * @param sourceMap      Karte in der die Selektion vorgenommen wurde
+   * @param sourceLayer    Layer aus dem die Features stammen
+   * @param point          Punkt der selektiert wurde
+   * @param result         selektierters Teil-Raster
+   */
+  public GridCoverageValueSelectedEvent(JMapPane sourceMap, MapLayer sourceLayer, Point2D point, double[] result) {
+    this(sourceMap,sourceLayer,point,result,null);
+  }
+
+  /**
+   * Liefert den selektierten Punkt.
+   */
+  public Point2D getSelectionPoint() {
+    return point;
+  }
+
+}

Modified: trunk/src/schmitzm/geotools/map/event/JEditorPaneEvent.java
===================================================================
--- trunk/src/schmitzm/geotools/map/event/JEditorPaneEvent.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/map/event/JEditorPaneEvent.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,64 +1,82 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.map.event;
-
-import org.geotools.map.MapLayer;
-
-import schmitzm.geotools.gui.JEditorPane;
-import schmitzm.geotools.gui.JEditorPane.EditorMode;
-
-/**
- * Diese Klasse stellt ein allgemeines Ereignis dar, das ein
- * {@link JEditorPane} ausloest.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public abstract class JEditorPaneEvent extends JMapPaneEvent {
-  /** Das bearbeitete Layer. */
-  protected MapLayer layer = null;
-  /** Bearbeitungs-Modus (zum Zeitpunkt des Events) */
-  protected EditorMode editorMode = null;
-
-  /**
-   * Erzeugt ein neues Ereignis.
-   * @param sourceMap      Karte in der die Veraenderung vorgenommen wurde
-   * @param sourceLayer    bearbeitetes Layer
-   * @param sourceObject   Objekt, das die Aenderung initiiert hat (wenn {@code null},
-   *                       wird das MapPane als Ausloeser gesetzt)
-   */
-  public JEditorPaneEvent(JEditorPane sourceMap, MapLayer sourceLayer, Object sourceObject) {
-    super(sourceMap, sourceObject);
-    this.layer = sourceLayer;
-    this.editorMode = sourceMap.getEditorMode();
-  }
-
-  /**
-   * Liefert das {@link JEditorPane}, das das Ereignis ausgeloest hat.
-   */
-  public JEditorPane getSource() {
-    return(JEditorPane)super.getSource();
-  }
-
-  /**
-   * Liefert das bearbeitete Layer.
-   */
-  public MapLayer getEditedLayer() {
-    return layer;
-  }
-
-  /**
-   * Liefert den Bearbeitungsmodus zum Zeitpunkt des Events.
-   */
-  public EditorMode getEditorMode() {
-    return editorMode;
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.map.event;
+
+import org.geotools.map.MapLayer;
+
+import schmitzm.geotools.gui.JEditorPane;
+import schmitzm.geotools.gui.JEditorPane.EditorMode;
+
+/**
+ * Diese Klasse stellt ein allgemeines Ereignis dar, das ein
+ * {@link JEditorPane} ausloest.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public abstract class JEditorPaneEvent extends JMapPaneEvent {
+  /** Das bearbeitete Layer. */
+  protected MapLayer layer = null;
+  /** Bearbeitungs-Modus (zum Zeitpunkt des Events) */
+  protected EditorMode editorMode = null;
+
+  /**
+   * Erzeugt ein neues Ereignis.
+   * @param sourceMap      Karte in der die Veraenderung vorgenommen wurde
+   * @param sourceLayer    bearbeitetes Layer
+   * @param sourceObject   Objekt, das die Aenderung initiiert hat (wenn {@code null},
+   *                       wird das MapPane als Ausloeser gesetzt)
+   */
+  public JEditorPaneEvent(JEditorPane sourceMap, MapLayer sourceLayer, Object sourceObject) {
+    super(sourceMap, sourceObject);
+    this.layer = sourceLayer;
+    this.editorMode = sourceMap.getEditorMode();
+  }
+
+  /**
+   * Liefert das {@link JEditorPane}, das das Ereignis ausgeloest hat.
+   */
+  public JEditorPane getSource() {
+    return(JEditorPane)super.getSource();
+  }
+
+  /**
+   * Liefert das bearbeitete Layer.
+   */
+  public MapLayer getEditedLayer() {
+    return layer;
+  }
+
+  /**
+   * Liefert den Bearbeitungsmodus zum Zeitpunkt des Events.
+   */
+  public EditorMode getEditorMode() {
+    return editorMode;
+  }
+}

Modified: trunk/src/schmitzm/geotools/map/event/JMapPaneEvent.java
===================================================================
--- trunk/src/schmitzm/geotools/map/event/JMapPaneEvent.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/map/event/JMapPaneEvent.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,60 +1,78 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.map.event;
-
-import schmitzm.geotools.gui.JMapPane;
-
-/**
- * Diese Klasse stellt ein Ereignis dar, das von einem {@link JMapPane}
- * ausgeloest wurde (z.B. Aenderung der Aufloesung).
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public abstract class JMapPaneEvent {
-  /** Beinhaltet das {@link JMapPane}, das das Ereignis ausgeloest hat */
-  protected JMapPane source = null;
-  /** Beinhaltet ein Objekt, das das Ereignis initiiert hat */
-  protected Object sourceObject = null;
-
-  /**
-   * Erzeugt ein neues Ereignis.
-   * @param source {@link JMapPane}, das das Ereignis ausgeloest hat
-   * @param sourceObject Objeckt, das das Ereignis initiiert hat (wenn {@code null},
-   *        wird das MapPane als Ausloeser gesetzt)
-   */
-  public JMapPaneEvent(JMapPane source, Object sourceObject) {
-    this.source       = source;
-    this.sourceObject = (sourceObject != null) ? sourceObject : source;
-  }
-
-  /**
-   * Erzeugt ein neues Ereignis.
-   * @param source {@link JMapPane}, das das Ereignis ausgeloest hat
-   */
-  public JMapPaneEvent(JMapPane source) {
-    this(source,null);
-  }
-
-  /**
-   * Liefert das {@link JMapPane}, das das Ereignis ausgeloest hat.
-   */
-  public JMapPane getSource() {
-    return source;
-  }
-
-  /**
-   * Liefert das Object, das das Ereignis initiiert hat.
-   */
-  public Object getSourceObject() {
-    return sourceObject;
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.map.event;
+
+import schmitzm.geotools.gui.JMapPane;
+
+/**
+ * Diese Klasse stellt ein Ereignis dar, das von einem {@link JMapPane}
+ * ausgeloest wurde (z.B. Aenderung der Aufloesung).
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public abstract class JMapPaneEvent {
+  /** Beinhaltet das {@link JMapPane}, das das Ereignis ausgeloest hat */
+  protected JMapPane source = null;
+  /** Beinhaltet ein Objekt, das das Ereignis initiiert hat */
+  protected Object sourceObject = null;
+
+  /**
+   * Erzeugt ein neues Ereignis.
+   * @param source {@link JMapPane}, das das Ereignis ausgeloest hat
+   * @param sourceObject Objeckt, das das Ereignis initiiert hat (wenn {@code null},
+   *        wird das MapPane als Ausloeser gesetzt)
+   */
+  public JMapPaneEvent(JMapPane source, Object sourceObject) {
+    this.source       = source;
+    this.sourceObject = (sourceObject != null) ? sourceObject : source;
+  }
+
+  /**
+   * Erzeugt ein neues Ereignis.
+   * @param source {@link JMapPane}, das das Ereignis ausgeloest hat
+   */
+  public JMapPaneEvent(JMapPane source) {
+    this(source,null);
+  }
+
+  /**
+   * Liefert das {@link JMapPane}, das das Ereignis ausgeloest hat.
+   */
+  public JMapPane getSource() {
+    return source;
+  }
+
+  /**
+   * Liefert das Object, das das Ereignis initiiert hat.
+   */
+  public Object getSourceObject() {
+    return sourceObject;
+  }
+}

Modified: trunk/src/schmitzm/geotools/map/event/JMapPaneListener.java
===================================================================
--- trunk/src/schmitzm/geotools/map/event/JMapPaneListener.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/map/event/JMapPaneListener.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,30 +1,48 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.map.event;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+// fuer Doku
+import schmitzm.geotools.gui.JMapPane;
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.map.event;
-
-// fuer Doku
-import schmitzm.geotools.gui.JMapPane;
-
-/**
- * Diese Klasse stellt einen Listener fuer Ereignisse des {@link JMapPane}
- * dar (z.B. Aenderung der Aufloesung).
- * @see JMapPaneEvent
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public interface JMapPaneListener {
-  /**
-   * Verarbeitet ein JMapPane-Ereignis.
-   * @param e Ereignis
-   */
-  public void performMapPaneEvent(JMapPaneEvent e);
-}
+/**
+ * Diese Klasse stellt einen Listener fuer Ereignisse des {@link JMapPane}
+ * dar (z.B. Aenderung der Aufloesung).
+ * @see JMapPaneEvent
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public interface JMapPaneListener {
+  /**
+   * Verarbeitet ein JMapPane-Ereignis.
+   * @param e Ereignis
+   */
+  public void performMapPaneEvent(JMapPaneEvent e);
+}

Modified: trunk/src/schmitzm/geotools/map/event/LayerEditCanceledEvent.java
===================================================================
--- trunk/src/schmitzm/geotools/map/event/LayerEditCanceledEvent.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/map/event/LayerEditCanceledEvent.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,36 +1,54 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.map.event;
-
-import org.geotools.map.MapLayer;
-
-import schmitzm.geotools.gui.JEditorPane;
-
-/**
- * Diese Klasse stellt ein Ereignis dar, das ein {@link JEditorPane} ausloest,
- * wenn der Anwender die Bearbeitung eines Layers abgebrochen hat.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class LayerEditCanceledEvent extends JEditorPaneEvent {
-  /**
-   * Erzeugt ein neues Ereignis.
-   * @param sourceMap      Karte in der die Veraenderung vorgenommen wurde
-   * @param sourceLayer    Layer dessen Bearbeitung abgebrochen wurde ({@code null}, wenn
-   *                       ein komplett neues Layer abgebrochen wurde)
-   * @param sourceObject   Objekt, das die Aenderung initiiert hat (wenn {@code null},
-   *                       wird das MapPane als Ausloeser gesetzt)
-   */
-  public LayerEditCanceledEvent(JEditorPane sourceMap, MapLayer sourceLayer, Object sourceObject) {
-    super(sourceMap, sourceLayer, sourceObject);
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.map.event;
+
+import org.geotools.map.MapLayer;
+
+import schmitzm.geotools.gui.JEditorPane;
+
+/**
+ * Diese Klasse stellt ein Ereignis dar, das ein {@link JEditorPane} ausloest,
+ * wenn der Anwender die Bearbeitung eines Layers abgebrochen hat.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class LayerEditCanceledEvent extends JEditorPaneEvent {
+  /**
+   * Erzeugt ein neues Ereignis.
+   * @param sourceMap      Karte in der die Veraenderung vorgenommen wurde
+   * @param sourceLayer    Layer dessen Bearbeitung abgebrochen wurde ({@code null}, wenn
+   *                       ein komplett neues Layer abgebrochen wurde)
+   * @param sourceObject   Objekt, das die Aenderung initiiert hat (wenn {@code null},
+   *                       wird das MapPane als Ausloeser gesetzt)
+   */
+  public LayerEditCanceledEvent(JEditorPane sourceMap, MapLayer sourceLayer, Object sourceObject) {
+    super(sourceMap, sourceLayer, sourceObject);
+  }
+}

Modified: trunk/src/schmitzm/geotools/map/event/LayerEditFinishedEvent.java
===================================================================
--- trunk/src/schmitzm/geotools/map/event/LayerEditFinishedEvent.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/map/event/LayerEditFinishedEvent.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,35 +1,53 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.map.event;
-
-import org.geotools.map.MapLayer;
-
-import schmitzm.geotools.gui.JEditorPane;
-
-/**
- * Diese Klasse stellt ein Ereignis dar, das ein {@link JEditorPane} ausloest,
- * wenn der Anwender die Bearbeitung eines Layers (erfolgreich) beendet hat.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class LayerEditFinishedEvent extends JEditorPaneEvent {
-  /**
-   * Erzeugt ein neues Ereignis.
-   * @param sourceMap      Karte in der die Veraenderung vorgenommen wird
-   * @param sourceLayer    Layer dessen Bearbeitung beendet wurde
-   * @param sourceObject   Objekt, das die Aenderung initiiert hat (wenn {@code null},
-   *                       wird das MapPane als Ausloeser gesetzt)
-   */
-  public LayerEditFinishedEvent(JEditorPane sourceMap, MapLayer sourceLayer, Object sourceObject) {
-    super(sourceMap, sourceLayer, sourceObject);
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.map.event;
+
+import org.geotools.map.MapLayer;
+
+import schmitzm.geotools.gui.JEditorPane;
+
+/**
+ * Diese Klasse stellt ein Ereignis dar, das ein {@link JEditorPane} ausloest,
+ * wenn der Anwender die Bearbeitung eines Layers (erfolgreich) beendet hat.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class LayerEditFinishedEvent extends JEditorPaneEvent {
+  /**
+   * Erzeugt ein neues Ereignis.
+   * @param sourceMap      Karte in der die Veraenderung vorgenommen wird
+   * @param sourceLayer    Layer dessen Bearbeitung beendet wurde
+   * @param sourceObject   Objekt, das die Aenderung initiiert hat (wenn {@code null},
+   *                       wird das MapPane als Ausloeser gesetzt)
+   */
+  public LayerEditFinishedEvent(JEditorPane sourceMap, MapLayer sourceLayer, Object sourceObject) {
+    super(sourceMap, sourceLayer, sourceObject);
+  }
+}

Modified: trunk/src/schmitzm/geotools/map/event/LayerEditStartedEvent.java
===================================================================
--- trunk/src/schmitzm/geotools/map/event/LayerEditStartedEvent.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/map/event/LayerEditStartedEvent.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,35 +1,53 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.map.event;
-
-import org.geotools.map.MapLayer;
-
-import schmitzm.geotools.gui.JEditorPane;
-
-/**
- * Diese Klasse stellt ein Ereignis dar, das ein {@link JEditorPane} ausloest,
- * wenn der Anwender die Bearbeitung eines Layers beginnt.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class LayerEditStartedEvent extends JEditorPaneEvent {
-  /**
-   * Erzeugt ein neues Ereignis.
-   * @param sourceMap      Karte in der die Veraenderung vorgenommen wird
-   * @param sourceLayer    Layer dessen Bearbeitung gestartet wird
-   * @param sourceObject   Objekt, das die Aenderung initiiert hat (wenn {@code null},
-   *                       wird das MapPane als Ausloeser gesetzt)
-   */
-  public LayerEditStartedEvent(JEditorPane sourceMap, MapLayer sourceLayer, Object sourceObject) {
-    super(sourceMap, sourceLayer, sourceObject);
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.map.event;
+
+import org.geotools.map.MapLayer;
+
+import schmitzm.geotools.gui.JEditorPane;
+
+/**
+ * Diese Klasse stellt ein Ereignis dar, das ein {@link JEditorPane} ausloest,
+ * wenn der Anwender die Bearbeitung eines Layers beginnt.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class LayerEditStartedEvent extends JEditorPaneEvent {
+  /**
+   * Erzeugt ein neues Ereignis.
+   * @param sourceMap      Karte in der die Veraenderung vorgenommen wird
+   * @param sourceLayer    Layer dessen Bearbeitung gestartet wird
+   * @param sourceObject   Objekt, das die Aenderung initiiert hat (wenn {@code null},
+   *                       wird das MapPane als Ausloeser gesetzt)
+   */
+  public LayerEditStartedEvent(JEditorPane sourceMap, MapLayer sourceLayer, Object sourceObject) {
+    super(sourceMap, sourceLayer, sourceObject);
+  }
+}

Modified: trunk/src/schmitzm/geotools/map/event/MapAreaChangedEvent.java
===================================================================
--- trunk/src/schmitzm/geotools/map/event/MapAreaChangedEvent.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/map/event/MapAreaChangedEvent.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,52 +1,70 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.map.event;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+import schmitzm.geotools.gui.JMapPane;
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+import com.vividsolutions.jts.geom.Envelope;
 
-package schmitzm.geotools.map.event;
-
-import schmitzm.geotools.gui.JMapPane;
+/**
+ * Diese Klasse stellt ein Ereignis dar, das ein {@link JMapPane} ausloest,
+ * wenn sich die Ausdehnung der dargestellte Karten-Ausschnitt aendert.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class MapAreaChangedEvent extends JMapPaneEvent {
+  private Envelope oldEnvelope = null;
+  private Envelope newEnvelope = null;
 
-import com.vividsolutions.jts.geom.Envelope;
-
-/**
- * Diese Klasse stellt ein Ereignis dar, das ein {@link JMapPane} ausloest,
- * wenn sich die Ausdehnung der dargestellte Karten-Ausschnitt aendert.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class MapAreaChangedEvent extends JMapPaneEvent {
-  private Envelope oldEnvelope = null;
-  private Envelope newEnvelope = null;
-
-  /**
-   * Erzeugt ein neues Ereignis.
-   * @param oldEnvelope vormalige Ausdehnung
-   * @param newEnvelope neue Ausdehnung
-   */
-  public MapAreaChangedEvent(JMapPane source, Envelope oldEnvelope, Envelope newEnvelope) {
-    super(source);
-    this.oldEnvelope = oldEnvelope;
-    this.newEnvelope = newEnvelope;
-  }
-
-  /**
-   * Liefert die alte Karten-Ausdehnung.
-   */
-  public Envelope getOldMapArea() {
-    return oldEnvelope;
-  }
-
-  /**
-   * Liefert die neue Karten-Ausdehnung.
-   */
-  public Envelope getNewMapArea() {
-    return newEnvelope;
-  }
-}
+  /**
+   * Erzeugt ein neues Ereignis.
+   * @param oldEnvelope vormalige Ausdehnung
+   * @param newEnvelope neue Ausdehnung
+   */
+  public MapAreaChangedEvent(JMapPane source, Envelope oldEnvelope, Envelope newEnvelope) {
+    super(source);
+    this.oldEnvelope = oldEnvelope;
+    this.newEnvelope = newEnvelope;
+  }
+
+  /**
+   * Liefert die alte Karten-Ausdehnung.
+   */
+  public Envelope getOldMapArea() {
+    return oldEnvelope;
+  }
+
+  /**
+   * Liefert die neue Karten-Ausdehnung.
+   */
+  public Envelope getNewMapArea() {
+    return newEnvelope;
+  }
+}

Modified: trunk/src/schmitzm/geotools/map/event/MapContextSynchronizer.java
===================================================================
--- trunk/src/schmitzm/geotools/map/event/MapContextSynchronizer.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/map/event/MapContextSynchronizer.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,67 +1,86 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.geotools.map.event;
-
-import org.geotools.geometry.jts.ReferencedEnvelope;
-import org.geotools.map.MapContext;
-import org.geotools.map.event.MapBoundsEvent;
-import org.geotools.map.event.MapBoundsListener;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-
-/**
- * This {@link MapBoundsListener} listens to {@link MapBoundsEvent MapBoundsEvents}
- * and transfers the change of {@link CoordinateReferenceSystem} and "AreaOfInterest"
- * to the connected {@link MapContext}, so this {@link MapContext} has always the
- * same CRS and AreaOfInterest like the {@link MapContex} this Listener is added to.
- * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
- */
-public class MapContextSynchronizer implements MapBoundsListener {
-  /** {@link MapContext} the changes by a {@link MapBoundsEvent} are
-   *  transfered to. */
-  protected MapContext mapContext = null;
-
-  /**
-   * Creates a new synchronizer.
-   * @param mapContext the {@link MapContext} the changes by a
-   *                   {@link MapBoundsEvent} are transfered to
-   */
-  public MapContextSynchronizer(MapContext mapContext) {
-    this.mapContext = mapContext;
-  }
-
-  /**
-   * Invoked when the CRS or AreaOfInterest of a connected {@link MapContext}
-   * changes.
-   * @param e an event
-   */
-  public void mapBoundsChanged(MapBoundsEvent e) {
-    if ( mapContext == null )
-      return;
-
-    MapContext                eventContext = (MapContext)e.getSource();
-    ReferencedEnvelope        eventAOI     = eventContext.getAreaOfInterest();
-    CoordinateReferenceSystem eventCRS     = eventContext.getCoordinateReferenceSystem();
-    ReferencedEnvelope        currAOI      = mapContext.getAreaOfInterest();
-    CoordinateReferenceSystem currCRS      = mapContext.getCoordinateReferenceSystem();
-
-    try {
-      // check the CRS for changes
-      if ( currCRS == null || !currCRS.equals(eventCRS) )
-        mapContext.setCoordinateReferenceSystem( eventCRS );
-      // check the AreaOfInterst for changes
-      if ( currAOI == null || !currAOI.equals(eventAOI) )
-        mapContext.setAreaOfInterest( eventAOI );
-    } catch (Exception err) {
-      throw new RuntimeException(err);
-    }
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.map.event;
+
+import org.geotools.geometry.jts.ReferencedEnvelope;
+import org.geotools.map.MapContext;
+import org.geotools.map.event.MapBoundsEvent;
+import org.geotools.map.event.MapBoundsListener;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+
+/**
+ * This {@link MapBoundsListener} listens to {@link MapBoundsEvent MapBoundsEvents}
+ * and transfers the change of {@link CoordinateReferenceSystem} and "AreaOfInterest"
+ * to the connected {@link MapContext}, so this {@link MapContext} has always the
+ * same CRS and AreaOfInterest like the {@link MapContex} this Listener is added to.
+ * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
+ */
+public class MapContextSynchronizer implements MapBoundsListener {
+  /** {@link MapContext} the changes by a {@link MapBoundsEvent} are
+   *  transfered to. */
+  protected MapContext mapContext = null;
+
+  /**
+   * Creates a new synchronizer.
+   * @param mapContext the {@link MapContext} the changes by a
+   *                   {@link MapBoundsEvent} are transfered to
+   */
+  public MapContextSynchronizer(MapContext mapContext) {
+    this.mapContext = mapContext;
+  }
+
+  /**
+   * Invoked when the CRS or AreaOfInterest of a connected {@link MapContext}
+   * changes.
+   * @param e an event
+   */
+  public void mapBoundsChanged(MapBoundsEvent e) {
+    if ( mapContext == null )
+      return;
+
+    MapContext                eventContext = (MapContext)e.getSource();
+    ReferencedEnvelope        eventAOI     = eventContext.getAreaOfInterest();
+    CoordinateReferenceSystem eventCRS     = eventContext.getCoordinateReferenceSystem();
+    ReferencedEnvelope        currAOI      = mapContext.getAreaOfInterest();
+    CoordinateReferenceSystem currCRS      = mapContext.getCoordinateReferenceSystem();
+
+    try {
+      // check the CRS for changes
+      if ( currCRS == null || !currCRS.equals(eventCRS) )
+        mapContext.setCoordinateReferenceSystem( eventCRS );
+      // check the AreaOfInterst for changes
+      if ( currAOI == null || !currAOI.equals(eventAOI) )
+        mapContext.setAreaOfInterest( eventAOI );
+    } catch (Exception err) {
+      throw new RuntimeException(err);
+    }
+  }
+
+}

Modified: trunk/src/schmitzm/geotools/map/event/MapLayerAdapter.java
===================================================================
--- trunk/src/schmitzm/geotools/map/event/MapLayerAdapter.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/map/event/MapLayerAdapter.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,42 +1,60 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.map.event;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+import org.geotools.map.event.MapLayerEvent;
+import org.geotools.map.event.MapLayerListener;
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+/**
+ * Diese Klasse bildet eine Basis-Implementierung von
+ * {@link MapLayerListener org.geotools.map.event.MapLayerListener}, deren
+ * Methoden nichts machen.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of  Bonn/Germany)
+ * @version 1.0
+ */
+public class MapLayerAdapter implements MapLayerListener {
+  /**
+   * Wird aufgerufen, wenn ein Layer verborgen wird. Macht nichts.
+   */
+  public void layerHidden(MapLayerEvent e) {
+  }
 
-package schmitzm.geotools.map.event;
-
-import org.geotools.map.event.MapLayerEvent;
-import org.geotools.map.event.MapLayerListener;
-
-/**
- * Diese Klasse bildet eine Basis-Implementierung von
- * {@link MapLayerListener org.geotools.map.event.MapLayerListener}, deren
- * Methoden nichts machen.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of  Bonn/Germany)
- * @version 1.0
- */
-public class MapLayerAdapter implements MapLayerListener {
-  /**
-   * Wird aufgerufen, wenn ein Layer verborgen wird. Macht nichts.
-   */
-  public void layerHidden(MapLayerEvent e) {
-  }
-
-  /**
-   * Wird aufgerufen, wenn sich ein Layer veraendert. Macht nichts.
-   */
-  public void layerChanged(MapLayerEvent e) {
-  }
-
-  /**
-   * Wird aufgerufen, wenn ein Layer angezeigt wird. Macht nichts.
-   */
-  public void layerShown(MapLayerEvent e) {
-  }
-}
+  /**
+   * Wird aufgerufen, wenn sich ein Layer veraendert. Macht nichts.
+   */
+  public void layerChanged(MapLayerEvent e) {
+  }
+
+  /**
+   * Wird aufgerufen, wenn ein Layer angezeigt wird. Macht nichts.
+   */
+  public void layerShown(MapLayerEvent e) {
+  }
+}

Modified: trunk/src/schmitzm/geotools/map/event/MapLayerListAdapter.java
===================================================================
--- trunk/src/schmitzm/geotools/map/event/MapLayerListAdapter.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/map/event/MapLayerListAdapter.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,53 +1,71 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.map.event;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.map.event;
-
 import org.geotools.map.MapContext;
 import org.geotools.map.event.MapLayerListEvent;
 import org.geotools.map.event.MapLayerListListener;
-
-/**
- * Diese Klasse bildet eine Basis-Implementierung von
- * {@link MapLayerListListener org.geotools.map.event.MapLayerListListener}, deren
- * Methoden nichts machen.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of  Bonn/Germany)
- * @version 1.0
- */
-public class MapLayerListAdapter implements MapLayerListListener {
-  /**
-   * Wird aufgerufen, wenn ein Layer dem {@link MapContext} hinzugefuegt wurde.
-   * Macht nichts.
-   */
-  public void layerAdded(MapLayerListEvent e) {
-  }
-
-  /**
-   * Wird aufgerufen, wenn sich ein Layer veraendert. Macht nichts.
-   */
-  public void layerChanged(MapLayerListEvent e) {
-  }
-
-  /**
-   * Wird aufgerufen, wenn ein Layer in eine andere Ebene verschoben wurde.
-   * Macht nichts.
-   */
-  public void layerMoved(MapLayerListEvent e) {
-  }
-
-  /**
-   * Wird aufgerufen, wenn ein Layer aus dem {@link MapContext} entfernt wurde.
-   * Macht nichts.
-   */
-  public void layerRemoved(MapLayerListEvent e) {
-  }
-
-}
+
+/**
+ * Diese Klasse bildet eine Basis-Implementierung von
+ * {@link MapLayerListListener org.geotools.map.event.MapLayerListListener}, deren
+ * Methoden nichts machen.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of  Bonn/Germany)
+ * @version 1.0
+ */
+public class MapLayerListAdapter implements MapLayerListListener {
+  /**
+   * Wird aufgerufen, wenn ein Layer dem {@link MapContext} hinzugefuegt wurde.
+   * Macht nichts.
+   */
+  public void layerAdded(MapLayerListEvent e) {
+  }
+
+  /**
+   * Wird aufgerufen, wenn sich ein Layer veraendert. Macht nichts.
+   */
+  public void layerChanged(MapLayerListEvent e) {
+  }
+
+  /**
+   * Wird aufgerufen, wenn ein Layer in eine andere Ebene verschoben wurde.
+   * Macht nichts.
+   */
+  public void layerMoved(MapLayerListEvent e) {
+  }
+
+  /**
+   * Wird aufgerufen, wenn ein Layer aus dem {@link MapContext} entfernt wurde.
+   * Macht nichts.
+   */
+  public void layerRemoved(MapLayerListEvent e) {
+  }
+
+}

Modified: trunk/src/schmitzm/geotools/map/event/ObjectSelectionEvent.java
===================================================================
--- trunk/src/schmitzm/geotools/map/event/ObjectSelectionEvent.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/map/event/ObjectSelectionEvent.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,70 +1,88 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.map.event;
-
-import org.geotools.map.MapLayer;
-
-import schmitzm.geotools.gui.JMapPane;
-
-import com.vividsolutions.jts.geom.Envelope;
-
-/**
- * Diese Klasse stellt eine Oberklasse fuer die Ereignisse dar, die ein
- * {@link JMapPane} ausloest, wenn der Anwender einen Bereich in der Karte ausgewaehlt hat
- * und dabei Objekte selektiert wurde.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class ObjectSelectionEvent<E> extends GeneralSelectionEvent {
-  private MapLayer          sourceLayer = null;
-  private E                 result      = null;
-
-  /**
-   * Erzeugt ein neues Ereignis.
-   * @param sourceMap      Karte in der die Selektion vorgenommen wurde
-   * @param sourceLayer    Layer aus dem die Features stammen
-   * @param envelope       Bereich der selektiert wurde
-   * @param result         selektierte Objekte
-   * @param sourceObject   Objekt, das die Selektion initiiert hat (wenn {@code null},
-   *                       wird das MapPane als Ausloeser gesetzt)
-   */
-  public ObjectSelectionEvent(JMapPane sourceMap, MapLayer sourceLayer, Envelope envelope, E result, Object sourceObject) {
-    super(sourceMap,envelope,sourceObject);
-    this.sourceLayer = sourceLayer;
-    this.result      = result;
-  }
-
-  /**
-   * Erzeugt ein neues Ereignis.
-   * @param sourceMap      Karte in der die Selektion vorgenommen wurde
-   * @param sourceLayer    Layer aus dem die Features stammen
-   * @param envelope       Bereich der selektiert wurde
-   * @param result         selektierte Objekte
-   */
-  public ObjectSelectionEvent(JMapPane sourceMap, MapLayer sourceLayer, Envelope envelope, E result) {
-    this(sourceMap,sourceLayer,envelope, result, null);
-  }
-  /**
-   * Liefert das Layer aus dem die Features stammen.
-   */
-  public MapLayer getSourceLayer() {
-    return sourceLayer;
-  }
-
-  /**
-   * Liefert die selektierten Objekte.
-   */
-  public E getSelectionResult() {
-    return result;
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.map.event;
+
+import org.geotools.map.MapLayer;
+
+import schmitzm.geotools.gui.JMapPane;
+
+import com.vividsolutions.jts.geom.Envelope;
+
+/**
+ * Diese Klasse stellt eine Oberklasse fuer die Ereignisse dar, die ein
+ * {@link JMapPane} ausloest, wenn der Anwender einen Bereich in der Karte ausgewaehlt hat
+ * und dabei Objekte selektiert wurde.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class ObjectSelectionEvent<E> extends GeneralSelectionEvent {
+  private MapLayer          sourceLayer = null;
+  private E                 result      = null;
+
+  /**
+   * Erzeugt ein neues Ereignis.
+   * @param sourceMap      Karte in der die Selektion vorgenommen wurde
+   * @param sourceLayer    Layer aus dem die Features stammen
+   * @param envelope       Bereich der selektiert wurde
+   * @param result         selektierte Objekte
+   * @param sourceObject   Objekt, das die Selektion initiiert hat (wenn {@code null},
+   *                       wird das MapPane als Ausloeser gesetzt)
+   */
+  public ObjectSelectionEvent(JMapPane sourceMap, MapLayer sourceLayer, Envelope envelope, E result, Object sourceObject) {
+    super(sourceMap,envelope,sourceObject);
+    this.sourceLayer = sourceLayer;
+    this.result      = result;
+  }
+
+  /**
+   * Erzeugt ein neues Ereignis.
+   * @param sourceMap      Karte in der die Selektion vorgenommen wurde
+   * @param sourceLayer    Layer aus dem die Features stammen
+   * @param envelope       Bereich der selektiert wurde
+   * @param result         selektierte Objekte
+   */
+  public ObjectSelectionEvent(JMapPane sourceMap, MapLayer sourceLayer, Envelope envelope, E result) {
+    this(sourceMap,sourceLayer,envelope, result, null);
+  }
+  /**
+   * Liefert das Layer aus dem die Features stammen.
+   */
+  public MapLayer getSourceLayer() {
+    return sourceLayer;
+  }
+
+  /**
+   * Liefert die selektierten Objekte.
+   */
+  public E getSelectionResult() {
+    return result;
+  }
+
+}

Modified: trunk/src/schmitzm/geotools/map/event/ScaleChangedEvent.java
===================================================================
--- trunk/src/schmitzm/geotools/map/event/ScaleChangedEvent.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/map/event/ScaleChangedEvent.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,50 +1,68 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.map.event;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+import schmitzm.geotools.gui.JMapPane;
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+/**
+ * Diese Klasse stellt ein Ereignis dar, das ein {@link JMapPane} ausloest,
+ * wenn sich die Skalierung/Aufloesung der Karte aendert.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class ScaleChangedEvent extends JMapPaneEvent {
+  private double oldScale = 0;
+  private double newScale = 0;
 
-package schmitzm.geotools.map.event;
-
-import schmitzm.geotools.gui.JMapPane;
-
-/**
- * Diese Klasse stellt ein Ereignis dar, das ein {@link JMapPane} ausloest,
- * wenn sich die Skalierung/Aufloesung der Karte aendert.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class ScaleChangedEvent extends JMapPaneEvent {
-  private double oldScale = 0;
-  private double newScale = 0;
-
-  /**
-   * Erzeugt ein neues Ereignis.
-   * @param oldScale vormalige Aufloesung
-   * @param newScale neue Aufloesung
-   */
-  public ScaleChangedEvent(JMapPane source, double oldScale, double newScale) {
-    super(source);
-    this.oldScale = oldScale;
-    this.newScale = newScale;
-  }
-
-  /**
-   * Liefert die alte Aufloesung.
-   */
-  public double getOldScale() {
-    return oldScale;
-  }
-
-  /**
-   * Liefert die neue Aufloesung.
-   */
-  public double getNewScale() {
-    return newScale;
-  }
-}
+  /**
+   * Erzeugt ein neues Ereignis.
+   * @param oldScale vormalige Aufloesung
+   * @param newScale neue Aufloesung
+   */
+  public ScaleChangedEvent(JMapPane source, double oldScale, double newScale) {
+    super(source);
+    this.oldScale = oldScale;
+    this.newScale = newScale;
+  }
+
+  /**
+   * Liefert die alte Aufloesung.
+   */
+  public double getOldScale() {
+    return oldScale;
+  }
+
+  /**
+   * Liefert die neue Aufloesung.
+   */
+  public double getNewScale() {
+    return newScale;
+  }
+}

Modified: trunk/src/schmitzm/geotools/styling/ColorMapManager.java
===================================================================
--- trunk/src/schmitzm/geotools/styling/ColorMapManager.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/styling/ColorMapManager.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,71 +1,89 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.styling;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+import java.util.HashMap;
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+import org.geotools.styling.ColorMap;
 
-package schmitzm.geotools.styling;
-
-import java.util.HashMap;
+/**
+ * Diese Klasse verwaltet eine Liste von {@linkplain ColorMap Farbpaletten}
+ * fuer Rasterdaten als Tupel ({@code Name}, {@link ColorMap}).
+ * Zudem kann eine Farbpalette als Standard deklariert werden.
+ * @author Martin Schmitz
+ * @version 1.0
+ */
+public class ColorMapManager extends HashMap<String,ColorMap> {
+  /** Name der Standard-Farbtabelle. */
+  protected String defaultColorMap = null;
 
-import org.geotools.styling.ColorMap;
-
-/**
- * Diese Klasse verwaltet eine Liste von {@linkplain ColorMap Farbpaletten}
- * fuer Rasterdaten als Tupel ({@code Name}, {@link ColorMap}).
- * Zudem kann eine Farbpalette als Standard deklariert werden.
- * @author Martin Schmitz
- * @version 1.0
- */
-public class ColorMapManager extends HashMap<String,ColorMap> {
-  /** Name der Standard-Farbtabelle. */
-  protected String defaultColorMap = null;
-
-  /**
-   * Erzeugt einen neuen {@code ColorMapManager}.
-   */
-  public ColorMapManager() {
-    super();
-  }
-
-  /**
-   * Fuegt dem Manager eine Farbpalette hinzu.
-   * @param name Bezeichnung der Farbpalette
-   * @param map  Farbpalette
-   * @param setDefault  ist dieses Flag gesetzt, wird diese Farbpalette als
-   *                    Standard festgelegt
-   */
-  public void put(String name, ColorMap map, boolean setDefault) {
-    put(name,map);
-    if ( setDefault )
-      setDefaultColorMap( name );
-  }
-
-  /**
-   * Setzt die Standard-Farbpalette.
-   * @param name Bezeichnung der Farbpalette
-   */
-  public void setDefaultColorMap(String name) {
-    defaultColorMap = name;
-  }
-
-  /**
-   * Liefert die Bezeichnung der Standard-Farbpalette.
-   */
-  public String getDefaultColorMapName() {
-    return defaultColorMap;
-  }
-
-  /**
-   * Liefert die Standard-Farbpalette.
-   */
-  public ColorMap getDefaultColorMap() {
-    return get(defaultColorMap);
-  }
-
-}
+  /**
+   * Erzeugt einen neuen {@code ColorMapManager}.
+   */
+  public ColorMapManager() {
+    super();
+  }
+
+  /**
+   * Fuegt dem Manager eine Farbpalette hinzu.
+   * @param name Bezeichnung der Farbpalette
+   * @param map  Farbpalette
+   * @param setDefault  ist dieses Flag gesetzt, wird diese Farbpalette als
+   *                    Standard festgelegt
+   */
+  public void put(String name, ColorMap map, boolean setDefault) {
+    put(name,map);
+    if ( setDefault )
+      setDefaultColorMap( name );
+  }
+
+  /**
+   * Setzt die Standard-Farbpalette.
+   * @param name Bezeichnung der Farbpalette
+   */
+  public void setDefaultColorMap(String name) {
+    defaultColorMap = name;
+  }
+
+  /**
+   * Liefert die Bezeichnung der Standard-Farbpalette.
+   */
+  public String getDefaultColorMapName() {
+    return defaultColorMap;
+  }
+
+  /**
+   * Liefert die Standard-Farbpalette.
+   */
+  public ColorMap getDefaultColorMap() {
+    return get(defaultColorMap);
+  }
+
+}

Modified: trunk/src/schmitzm/geotools/styling/StylingUtil.java
===================================================================
--- trunk/src/schmitzm/geotools/styling/StylingUtil.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/geotools/styling/StylingUtil.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,2116 +1,2134 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.geotools.styling;
-
-import java.awt.Color;
-import java.awt.Dimension;
-import java.awt.Graphics;
-import java.awt.image.BufferedImage;
-import java.io.ByteArrayInputStream;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileWriter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.Writer;
-import java.lang.reflect.Array;
-import java.net.URL;
-import java.nio.charset.Charset;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-import javax.swing.Box;
-import javax.swing.BoxLayout;
-import javax.swing.ImageIcon;
-import javax.swing.JLabel;
-import javax.units.Unit;
-import javax.xml.transform.TransformerException;
-
-import org.apache.log4j.Logger;
-import org.geotools.brewer.color.BrewerPalette;
-import org.geotools.brewer.color.PaletteSuitability;
-import org.geotools.brewer.color.SampleScheme;
-import org.geotools.coverage.Category;
-import org.geotools.coverage.GridSampleDimension;
-import org.geotools.coverage.grid.GridCoverage2D;
-import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader;
-import org.geotools.data.FeatureSource;
-import org.geotools.data.memory.MemoryFeatureCollection;
-import org.geotools.factory.CommonFactoryFinder;
-import org.geotools.factory.GeoTools;
-import org.geotools.feature.Feature;
-import org.geotools.feature.FeatureCollection;
-import org.geotools.feature.FeatureType;
-import org.geotools.feature.GeometryAttributeType;
-import org.geotools.filter.ConstantExpression;
-import org.geotools.gui.swing.ExceptionMonitor;
-import org.geotools.renderer.lite.RendererUtilities;
-import org.geotools.resources.i18n.Vocabulary;
-import org.geotools.resources.i18n.VocabularyKeys;
-import org.geotools.styling.ColorMap;
-import org.geotools.styling.ColorMapEntry;
-import org.geotools.styling.ColorMapEntryImpl;
-import org.geotools.styling.ColorMapImpl;
-import org.geotools.styling.ExternalGraphic;
-import org.geotools.styling.FeatureTypeStyle;
-import org.geotools.styling.FeatureTypeStyleImpl;
-import org.geotools.styling.Fill;
-import org.geotools.styling.Graphic;
-import org.geotools.styling.LineSymbolizer;
-import org.geotools.styling.Mark;
-import org.geotools.styling.PointSymbolizer;
-import org.geotools.styling.PolygonSymbolizer;
-import org.geotools.styling.RasterSymbolizer;
-import org.geotools.styling.RasterSymbolizerImpl;
-import org.geotools.styling.Rule;
-import org.geotools.styling.RuleImpl;
-import org.geotools.styling.SLDParser;
-import org.geotools.styling.SLDTransformer;
-import org.geotools.styling.Stroke;
-import org.geotools.styling.Style;
-import org.geotools.styling.StyleBuilder;
-import org.geotools.styling.StyleFactory;
-import org.geotools.styling.Symbolizer;
-import org.geotools.styling.TextSymbolizer;
-import org.geotools.util.NumberRange;
-import org.jdom.Element;
-import org.jdom.output.XMLOutputter;
-import org.opengis.coverage.grid.Grid;
-import org.opengis.coverage.grid.GridCoverage;
-import org.opengis.filter.Filter;
-import org.opengis.filter.FilterFactory2;
-import org.opengis.filter.expression.Expression;
-import org.opengis.filter.expression.Literal;
-import org.opengis.filter.expression.NilExpression;
-
-import schmitzm.geotools.FilterUtil;
-import schmitzm.geotools.feature.FeatureUtil;
-import schmitzm.geotools.feature.FeatureUtil.GeometryForm;
-import schmitzm.geotools.grid.GridUtil;
-import schmitzm.lang.LangUtil;
-import skrueger.geotools.LegendIconFeatureRenderer;
-import skrueger.i8n.Translation;
-
-import com.sun.xml.bind.StringInputStream;
-import com.vividsolutions.jts.geom.Geometry;
-import com.vividsolutions.jts.geom.LineString;
-import com.vividsolutions.jts.geom.MultiLineString;
-import com.vividsolutions.jts.geom.MultiPoint;
-import com.vividsolutions.jts.geom.MultiPolygon;
-import com.vividsolutions.jts.geom.Polygon;
-
-/**
- * Diese Klasse enthaelt Hilfsfunktionen zum GeoTools-Styling
- * 
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- *         (University of Bonn/Germany)
- * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
- * 
- * @version 1.1
- */
-public class StylingUtil {
-	private static final Logger LOGGER = Logger.getLogger(StylingUtil.class);
-	/** Transparente Farbe */
-	public static final Color TRANSPARENT_COLOR = new Color(0, 0, 0, 0);
-
-	/**
-	 * Standard-Instanz eines {@link StyleBuilder}.
-	 * 
-	 * @Deprecated Bitte nicht benutzen. Ich habe schlechte Efahrungen damit.
-	 *             Zumindest uin 2.4.
-	 */
-	public static final StyleBuilder STYLE_BUILDER = new StyleBuilder();
-
-	/** Standard-Instanz eines {@link SLDTransformer}. */
-	public final static SLDTransformer SLDTRANSFORMER = new SLDTransformer();
-
-	/**
-	 * Standard-Instanz eines {@link StyleBuilder}.
-	 * 
-	 * @deprecated wurde ersetzt durch {@link #STYLE_BUILDER}
-	 */
-	public static final StyleBuilder builder = STYLE_BUILDER;
-
-	/** Standard-Instanz einer {@link StyleFactory} */
-	public static final StyleFactory STYLE_FACTORY = CommonFactoryFinder
-			.getStyleFactory(GeoTools.getDefaultHints());
-
-	/**
-	 * Standard-Instanz einer {@link StyleFactory}
-	 * 
-	 * @deprecated wurde ersetzt durch {@link #STYLE_FACTORY}
-	 */
-	public static final StyleFactory styleFactory = STYLE_FACTORY;
-
-	/**
-	 * TODO SK The following constants are used to speed up
-	 * {@link #createSelectionStyle(Object)}. I will "redo" them soon and also
-	 * document them. This is still under construction. TODO SK
-	 */
-
-	static final Literal size0 = FeatureUtil.FILTER_FACTORY2.literal(13);
-	static final Literal size1 = FeatureUtil.FILTER_FACTORY2.literal(9);
-	static final Literal size2 = FeatureUtil.FILTER_FACTORY2.literal(7);
-	static final Literal size3 = FeatureUtil.FILTER_FACTORY2.literal(3);
-	static final Literal zeroLit = FeatureUtil.FILTER_FACTORY2.literal(0);
-
-	// static final Stroke SELECTION_STROKE1 =
-	// STYLE_FACTORY.createStroke(STYLE_BUILDER.colorExpression(Color.YELLOW),
-	// size2);
-
-	static final Stroke SELECTION_STROKE1 = STYLE_FACTORY.createStroke(
-			STYLE_BUILDER.colorExpression(Color.YELLOW.brighter()),
-			FeatureUtil.FILTER_FACTORY2.literal(4), FeatureUtil.FILTER_FACTORY2
-					.literal(1.), FeatureUtil.FILTER_FACTORY.literal("round"),
-			FeatureUtil.FILTER_FACTORY.literal("round"), new float[0],
-			FeatureUtil.FILTER_FACTORY2.literal(0), null, null);
-
-	static final Stroke SELECTION_STROKE2 = STYLE_FACTORY.createStroke(
-			STYLE_BUILDER.colorExpression(Color.BLACK),
-			FeatureUtil.FILTER_FACTORY2.literal(1.5),
-			FeatureUtil.FILTER_FACTORY2.literal(1.), FeatureUtil.FILTER_FACTORY
-					.literal("round"), FeatureUtil.FILTER_FACTORY
-					.literal("round"), new float[] { 3f, 3f },
-			FeatureUtil.FILTER_FACTORY2.literal(0), null, null);
-
-	static final Stroke SELECTION_STROKE3 = STYLE_FACTORY.createStroke(
-			STYLE_BUILDER.colorExpression(Color.WHITE),
-			FeatureUtil.FILTER_FACTORY2.literal(1.5),
-			FeatureUtil.FILTER_FACTORY2.literal(1.), FeatureUtil.FILTER_FACTORY
-					.literal("round"), FeatureUtil.FILTER_FACTORY
-					.literal("round"), new float[] { 3f, 3f },
-			FeatureUtil.FILTER_FACTORY2.literal(3), null, null);
-
-	static final Graphic SELECTION_GRAPHIC1 = STYLE_FACTORY.createGraphic(
-			new ExternalGraphic[0], new Mark[] { STYLE_FACTORY.createMark(
-					FeatureUtil.FILTER_FACTORY2.literal("square"), null,
-					STYLE_FACTORY.createFill(STYLE_BUILDER
-							.colorExpression(Color.WHITE)), size1, zeroLit) },
-			new org.geotools.styling.Symbol[0], FeatureUtil.FILTER_FACTORY2
-					.literal(1), size1, zeroLit);
-
-	static final Graphic SELECTION_GRAPHIC2 = STYLE_FACTORY.createGraphic(
-			new ExternalGraphic[0], new Mark[] { STYLE_FACTORY.createMark(
-					FeatureUtil.FILTER_FACTORY2.literal("circle"), null,
-					STYLE_FACTORY.createFill(STYLE_BUILDER
-							.colorExpression(Color.BLACK)), size2, zeroLit) },
-			new org.geotools.styling.Symbol[0], FeatureUtil.FILTER_FACTORY2
-					.literal(1), size2, zeroLit);
-
-	static final Graphic SELECTION_GRAPHIC3 = STYLE_FACTORY.createGraphic(
-			new ExternalGraphic[0], new Mark[] { STYLE_FACTORY.createMark(
-					FeatureUtil.FILTER_FACTORY2.literal("circle"), null,
-					STYLE_FACTORY.createFill(STYLE_BUILDER
-							.colorExpression(Color.YELLOW.brighter())), size3,
-					zeroLit) }, new org.geotools.styling.Symbol[0],
-			FeatureUtil.FILTER_FACTORY2.literal(1), size3, zeroLit);
-	static final Fill SELECTION_FILL1 = STYLE_FACTORY.createFill(STYLE_BUILDER
-			.colorExpression(Color.RED), null, FeatureUtil.FILTER_FACTORY2
-			.literal(1), STYLE_FACTORY.createGraphic(new ExternalGraphic[0],
-			new Mark[] { STYLE_FACTORY.createMark(FeatureUtil.FILTER_FACTORY2
-					.literal("circle"), null, STYLE_FACTORY
-					.createFill(STYLE_BUILDER.colorExpression(Color.RED)),
-					size3, zeroLit) }, new org.geotools.styling.Symbol[0],
-			FeatureUtil.FILTER_FACTORY2.literal(1), size3, zeroLit));
-
-	// /**
-	// * Up to three {@link Style styles} suitable to present selected {@link
-	// Feature features} are cached here. (SK)
-	// */
-	// private static Map<GeometryForm,Style> selectionStyles = new
-	// HashMap<GeometryForm, Style>();
-
-	/**
-	 * Erstellt einen Default-Style fuer ein Geo-Objekt.
-	 * 
-	 * @param object
-	 *            {@link GridCoverage2D},
-	 *            {@link org.geotools.coverage.grid.io.AbstractGridCoverage2DReader}
-	 *            oder {@link FeatureCollection}
-	 * @return {@code null} falls kein Style generiert werden kann
-	 * 
-	 */
-	public static Style createDefaultStyle(Object object) {
-		Style style = STYLE_FACTORY.createStyle(); // SK.. nicer default than
-		// null !
-
-		if (object instanceof GridCoverage2D
-				|| object instanceof org.geotools.coverage.grid.io.AbstractGridCoverage2DReader)
-			style = GridUtil.createDefaultStyle();
-
-		if (object instanceof FeatureCollection)
-			style = FeatureUtil.createDefaultStyle((FeatureCollection) object);
-
-		// SK.cb
-		if (object instanceof GeometryAttributeType)
-			style = FeatureUtil
-					.createDefaultStyle((GeometryAttributeType) object);
-
-		if (object instanceof FeatureSource)
-			style = FeatureUtil.createDefaultStyle(((FeatureSource) object)
-					.getSchema().getDefaultGeometry());
-		// SK.ce
-
-		return style;
-	}
-
-	/**
-	 * Erzeugt eine {@link Category} fuer die NoData-Werte transparent
-	 * dargestellt werden.
-	 * 
-	 * @param geoValue
-	 *            Geo-Wert, der NoData repraesentiert
-	 */
-	public static Category createNoDataCategory(double geoValue) {
-		return createNoDataCategory(0, geoValue);
-	}
-
-	/**
-	 * Erzeugt eine {@link Category} fuer die NoData-Werte transparent
-	 * dargestellt werden.
-	 * 
-	 * @param value
-	 *            Sample-Wert der Category
-	 * @param geoValue
-	 *            Geo-Wert, der NoData repraesentiert
-	 */
-	public static Category createNoDataCategory(int value, double geoValue) {
-		return new Category(Vocabulary
-				.formatInternational(VocabularyKeys.NODATA),
-				new Color[] { new Color(0, 0, 0, 0) }, new NumberRange(value,
-						value), new NumberRange(geoValue, geoValue));
-	}
-
-	/**
-	 * Erzeugt eine {@link GridSampleDimension} aus einer {@link ColorMap}.
-	 * 
-	 * @param name
-	 *            Name fuer die {@link GridSampleDimension}
-	 * @param colorMap
-	 *            fuer jeden Eintrag der {@link ColorMap} wird eine
-	 *            {@link Category} erzeugt
-	 * @param noDataValues
-	 *            Werte fuer die zusaetzliche {@link Category Categorys}
-	 *            erstellt werden, welche die transparent dargestellt werden
-	 *            (wenn {@code null} wird keine zusaetzliche {@link Category}
-	 *            erstellt)
-	 * @param unit
-	 *            Einheit der Werte in der {@link GridSampleDimension} (kann
-	 *            {@code null} sein)
-	 */
-	public static GridSampleDimension createDiscreteGridSampleDimension(
-			String name, ColorMap colorMap, double[] noDataValues, Unit unit) {
-		if (colorMap.getColorMapEntries().length == 0)
-			return null;
-
-		SortedMap<Integer, Category> categories = new TreeMap<Integer, Category>();
-		if (noDataValues == null)
-			noDataValues = new double[0];
-
-		// Create a (discrete) Category for each ColorMapEntry
-		int colorMapMin = Integer.MAX_VALUE;
-		int colorMapMax = Integer.MIN_VALUE;
-		for (ColorMapEntry cme : colorMap.getColorMapEntries()) {
-			String label = cme.getLabel();
-			Color color = getColorFromColorMapEntry(cme);
-			double value = getQuantityFromColorMapEntry(cme);
-			int intValue = (int) Math.round(value);
-			colorMapMin = Math.min(colorMapMin, intValue);
-			colorMapMax = Math.max(colorMapMax, intValue);
-			// if ( label == null || label.trim().equals("") )
-			// label = String.valueOf(intValue);
-			if (label == null)
-				label = "";
-			categories.put(intValue, new Category(label, new Color[] { color },
-					new NumberRange(intValue, intValue), new NumberRange(
-							intValue, intValue)));
-		}
-
-		// If NoData-Value is set, create an additional Category
-		for (double noDataValue : noDataValues) {
-			int value = categories.lastKey() + 10; // value not already used
-			categories.put(value, createNoDataCategory(value, noDataValue));
-			colorMapMin = Math.min(colorMapMin, (int) noDataValue);
-			colorMapMax = Math.max(colorMapMax, (int) noDataValue);
-		}
-
-		// Declare "all" values smaller/greater the color map values
-		// automatically as NoData
-		// int colorMapRange = colorMapMax - colorMapMin;
-		// double lowerStart = colorMapMin - 10000*colorMapRange;
-		// double higherEnd = colorMapMax + 10000*colorMapRange;
-		final int lowerStart = Integer.MIN_VALUE;
-		final int higherEnd = Integer.MAX_VALUE;
-		categories.put(colorMapMax + 10, new Category("_autoNoData1_",
-				new Color[] { new Color(0, 0, 0, 0) }, new NumberRange(
-						colorMapMax + 1, colorMapMax + 2), new NumberRange(
-						colorMapMax + 1, higherEnd)));
-		if (colorMapMin < colorMapMax)
-			categories.put(colorMapMin - 10, new Category(
-					"_autoNoData2_",
-					new Color[] { new Color(0, 0, 0, 0) },
-					// new NumberRange(colorMapMin-2, colorMapMin-1), //
-					// logischer, aber klappt nicht!?
-					new NumberRange(colorMapMax + 3, colorMapMax + 4),
-					new NumberRange(lowerStart, colorMapMin - 1)));
-
-		// Create the GridSampleDimension
-		GridSampleDimension gsd = new GridSampleDimension(name, categories
-				.values().toArray(new Category[0]), unit).geophysics(true);
-
-		for (Category c : (List<Category>) gsd.getCategories())
-			LOGGER.debug(c.toString());
-
-		return gsd;
-	}
-
-	/**
-	 * Liefert die Farbpalette zu einem Style, wenn der Style aus einem
-	 * {@link RasterSymbolizer} erzeugt wurde.
-	 * 
-	 * @param style
-	 *            Style Wenn <code>null</code>, dann wird style auf
-	 *            {@link GridUtil}.createDefaultStyle() gesetzt
-	 * @return <code>null</code> wenn der Style nicht auf einem
-	 *         {@link RasterSymbolizer} basiert.
-	 */
-	public static ColorMap getColorMapFromStyle(Style style) {
-
-		if (style == null)
-			style = GridUtil.createDefaultStyle();
-
-		FeatureTypeStyle[] fts = style.getFeatureTypeStyles();
-		if (fts == null || fts.length == 0)
-			return null;
-		Rule[] rule = fts[0].getRules();
-		if (rule == null || rule.length == 0)
-			return null;
-		Symbolizer[] symb = rule[0].getSymbolizers();
-		if (symb == null || symb.length == 0
-				|| !(symb[0] instanceof RasterSymbolizer))
-			return null;
-		return ((RasterSymbolizer) symb[0]).getColorMap();
-
-	}
-
-	/**
-	 * Ermittelt fuer einen Wert den {@link ColorMapEntry} aus einer
-	 * {@link ColorMap}.
-	 * 
-	 * @param value
-	 *            Wert
-	 * @return {@code null}, wenn in der {@link ColorMap} kein expliziter
-	 *         Eintrag fuer den Wert hinterlegt ist
-	 */
-	public static ColorMapEntry findColorMapEntry(ColorMap colorMap,
-			double value) {
-		for (ColorMapEntry entry : colorMap.getColorMapEntries())
-			if (value == getQuantityFromColorMapEntry(entry))
-				return entry;
-		return null;
-	}
-
-	/**
-	 * Kopiert eine {@link ColorMap}.
-	 * 
-	 * @return <code>null</code> wenn die uebergebene ColorMap <code>null</code>
-	 *         ist
-	 */
-	public static ColorMap cloneColorMap(ColorMap colorMap) {
-		if (colorMap == null)
-			return null;
-		ColorMapEntry[] entry = colorMap.getColorMapEntries();
-		ColorMap newColorMap = new ColorMapImpl();
-		newColorMap.setType(colorMap.getType()); // Hat noch keinen Effekt in
-		// 2.3.2, aber dennoch, SK
-		for (int i = 0; i < entry.length; i++)
-			newColorMap.addColorMapEntry(cloneColorMapEntry(entry[i]));
-		return newColorMap;
-	}
-
-	/**
-	 * Prueft, ob zwei {@link ColorMap}-Instanzen gleich sind.
-	 * 
-	 * @param cm1
-	 *            eine Farbpalette
-	 * @param cm2
-	 *            eine andere Farbpalette
-	 */
-	public static boolean colorMapsEqual(ColorMap cm1, ColorMap cm2) {
-		if (cm1 == null ^ cm2 == null)
-			return false;
-		if (cm1 == cm2)
-			return true;
-
-		ColorMapEntry[] cme1 = cm1.getColorMapEntries();
-		ColorMapEntry[] cme2 = cm2.getColorMapEntries();
-		if (cme1.length != cme2.length)
-			return false;
-
-		// Farbpaletten-Eintraege muessen gleich sein und in gleicher
-		// Reihenfolge vorliegen!
-		for (int i = 0; i < cme1.length; i++)
-			if (!colorMapEntriesEqual(cme1[i], cme2[i]))
-				return false;
-		return true;
-	}
-
-	/**
-	 * Prueft, ob zwei {@link ColorMapEntry}-Instanzen gleich sind. Dies ist der
-	 * Fall, wenn ihnen der gleiche Wert, die gleiche Farbe, die gleiche
-	 * Transparenz und das gleiche Label zugeordnet ist.
-	 * 
-	 * @param cme1
-	 *            ein Farbpaletten-Eintrag
-	 * @param cme2
-	 *            ein anderer Farbpaletten-Eintrag
-	 */
-	public static boolean colorMapEntriesEqual(ColorMapEntry cme1,
-			ColorMapEntry cme2) {
-		if (cme1 == null ^ cme2 == null)
-			return false;
-		if (cme1 == cme2)
-			return true;
-
-		// Label auf Gleichheit testen
-		if (cme1.getLabel() == null ^ cme2.getLabel() == null || cme1 != null
-				&& !cme1.getLabel().equals(cme2.getLabel()))
-			return false;
-		// Farbe auf Gleichheit testen
-		Color col1 = getColorFromColorMapEntry(cme1);
-		Color col2 = getColorFromColorMapEntry(cme2);
-		if (col1 == null ^ col2 == null || col1 != null && !col1.equals(col2))
-			return false;
-		// Wert auf Gleichheit testen
-		Double quan1 = getQuantityFromColorMapEntry(cme1);
-		Double quan2 = getQuantityFromColorMapEntry(cme2);
-		if (quan1 == null ^ quan2 == null || quan1 != null
-				&& !quan1.equals(quan2))
-			return false;
-		// Transparenz auf Gleichheit testen
-		Double op1 = getOpacityFromColorMapEntry(cme1);
-		Double op2 = getOpacityFromColorMapEntry(cme2);
-		if (op1 == null ^ op2 == null || op1 != null && !op1.equals(op2))
-			return false;
-
-		return true;
-	}
-
-	/**
-	 * Erzeugt einen {@link ColorMapEntry}.
-	 * 
-	 * @param label
-	 *            Label fuer den Farbpaletten-Eintrag
-	 * @param quantity
-	 *            Wert fuer den Farbpaletten-Eintrag
-	 * @param color
-	 *            Farbe fuer den Farbpaletten-Eintrag
-	 * @param opacity
-	 *            Transparenz fuer die Farbe des Farbpaletten-Eintrag
-	 */
-	public static ColorMapEntry createColorMapEntry(String label,
-			Double quantity, Color color, double opacity) {
-		ColorMapEntry newEntry = new ColorMapEntryImpl();
-		try {
-			newEntry.setLabel(label);
-			newEntry.setColor(STYLE_BUILDER.colorExpression(color));
-			newEntry.setOpacity(STYLE_BUILDER.literalExpression(opacity));
-			newEntry.setQuantity(STYLE_BUILDER.literalExpression(quantity));
-		} catch (Exception err) {
-		}
-		return newEntry;
-	}
-
-	/**
-	 * Kopiert einen {@link ColorMapEntry}.
-	 * 
-	 * @return <code>null</code> wenn der uebergebene ColorMapEntry
-	 *         <code>null</code> ist
-	 */
-	public static ColorMapEntry cloneColorMapEntry(ColorMapEntry colorMapEntry) {
-		if (colorMapEntry == null)
-			return null;
-
-		return createColorMapEntry(colorMapEntry.getLabel(),
-				getQuantityFromColorMapEntry(colorMapEntry),
-				getColorFromColorMapEntry(colorMapEntry),
-				getOpacityFromColorMapEntry(colorMapEntry));
-	}
-
-	/**
-	 * Liefert den Wert eines Farbpaletten-Eintrag.
-	 * 
-	 * @param expression
-	 *            Expression, die einen String oder einen Double liefert
-	 * @return {@code null}, wenn <code>null</code> uebergeben wird
-	 */
-	public static Double getQuantityFromExpression(Expression expression) {
-		// gt2-2.3.4:
-		// if ( expression == null || expression.getValue(null) == null )
-		// return null
-		// Object exprValue = evaluate.getValue(null);
-		// gt2-2.3.4:
-		if (expression == null || expression.evaluate(null) == null)
-			return null;
-		Object exprValue = expression.evaluate(null);
-
-		return (exprValue instanceof String) ? Double
-				.valueOf((String) exprValue) : ((Number) exprValue)
-				.doubleValue();
-	}
-
-	/**
-	 * Liefert den Wert eines Farbpaletten-Eintrag.
-	 * 
-	 * @param entry
-	 *            Farbpaletten-Eintrag
-	 * @return {@code null}, wenn <code>null</code> uebergeben wird
-	 */
-	public static Double getQuantityFromColorMapEntry(ColorMapEntry entry) {
-		if (entry == null)
-			return null;
-		return getQuantityFromExpression(entry.getQuantity());
-	}
-
-	/**
-	 * Setzt den Wert eines Farbpaletten-Eintrag.
-	 * 
-	 * @param entry
-	 *            Farbpaletten-Eintrag
-	 * @param quantity
-	 *            neuer Wert
-	 */
-	public static void setQuantityForColorMapEntry(ColorMapEntry entry,
-			double quantity) {
-		if (entry != null)
-			entry.setQuantity(STYLE_BUILDER.literalExpression(quantity));
-	}
-
-	/**
-	 * Liefert die Transparenz eines Farbpaletten-Eintrag.
-	 * 
-	 * @param expression
-	 *            Expression, die einen String oder einen Double liefert
-	 * @return 1.0, wenn <code>null</code> uebergeben wird
-	 */
-	public static Double getOpacityFromExpression(Expression expression) {
-		// gt2-2.3.4:
-		// if ( expression == null || expression.getValue(null) == null )
-		// return 1.0
-		// Object exprValue = evaluate.getValue(null);
-		// gt2-2.3.4:
-		if (expression == null || expression.evaluate(null) == null)
-			return 1.0;
-		Object exprValue = expression.evaluate(null);
-
-		return (exprValue instanceof String) ? Double
-				.valueOf((String) exprValue) : ((Number) exprValue)
-				.doubleValue();
-	}
-
-	/**
-	 * Liefert die Transparenz eines Farbpaletten-Eintrag.
-	 * 
-	 * @param entry
-	 *            Farbpaletten-Eintrag
-	 * @return 1.0, wenn <code>null</code> uebergeben wird
-	 */
-	public static Double getOpacityFromColorMapEntry(ColorMapEntry entry) {
-		if (entry == null)
-			return 1.0;
-		return getOpacityFromExpression(entry.getOpacity());
-	}
-
-	/**
-	 * Setzt die Transparenz eines Farbpaletten-Eintrag.
-	 * 
-	 * @param entry
-	 *            Farbpaletten-Eintrag
-	 * @param opacity
-	 *            Transparenzwert
-	 */
-	public static void setOpacityForColorMapEntry(ColorMapEntry entry,
-			double opacity) {
-		if (entry != null)
-			entry.setOpacity(STYLE_BUILDER.literalExpression(opacity));
-	}
-
-	/**
-	 * Liefert die Farbe eines Farbpaletten-Eintrag.
-	 * 
-	 * @param expression
-	 *            Expression, die einen String liefert
-	 */
-	public static Color getColorFromExpression(Expression expression) {
-		if (expression == null)
-			return null;
-
-		if (expression instanceof ConstantExpression) {
-			ConstantExpression a = (ConstantExpression) expression;
-			Object obj = a.getValue();
-			if (obj instanceof Color) {
-				return (Color) obj;
-			}
-		}
-
-		return Color.decode(expression.toString());
-
-		// Old way Martin did it:
-		// return Color.decode((String) expression.evaluate(null));
-
-	}
-
-	/**
-	 * Liefert die Farbe eines Farbpaletten-Eintrag.
-	 * 
-	 * @param entry
-	 *            Farbpaletten-Eintrag
-	 */
-	public static Color getColorFromColorMapEntry(ColorMapEntry entry) {
-		// if ( entry == null || entry.getColor() == null ||
-		// entry.getColor().getValue(null) == null ) // gt2-2.3.4
-		if (entry == null || entry.getColor() == null
-				|| entry.getColor().evaluate(null) == null) // gt2-2-4-2
-			return null;
-
-		// // Transparenz
-		// Double opacity = getOpacityFromColorMapEntry(entry);
-
-		return getColorFromExpression(entry.getColor());
-	}
-
-	/**
-	 * Setzt die Farbe eines Farbpaletten-Eintrag.
-	 * 
-	 * @param entry
-	 *            Farbpaletten-Eintrag
-	 * @param color
-	 *            eine Farbe
-	 */
-	public static void setColorForColorMapEntry(ColorMapEntry entry, Color color) {
-		if (entry != null)
-			entry.setColor(STYLE_BUILDER.colorExpression(color));
-	}
-
-	/**
-	 * Erzeugt einen {@link Style} aus einem {@linkplain Element JDOM-Element},
-	 * des eine SLD-Definition enthaelt
-	 * 
-	 * @param element
-	 *            Element mit SLD-Definition
-	 */
-	public static Style createStyleFromSLD(Element element) {
-		String xmlDefinition = new XMLOutputter().outputString(element);
-		Style[] style = loadSLD(new ByteArrayInputStream(xmlDefinition
-				.getBytes()));
-		return style == null || style.length == 0 ? null : style[0];
-	}
-
-	/**
-	 * Creates a {@link Style} for a {@link Grid} layer from a {@link ColorMap}
-	 * 
-	 * @param colorMap
-	 *            If null, then defaultStyle for Grid will be used
-	 * @param name
-	 *            The name to give to the Style. null will result in name=
-	 *            {@link GridUtil#UNNAMED_RASTER_STYLE_NAME} or
-	 *            GridUtil#DEFAULT_RASTER_STYLE_NAME} (if no colorMap is given).
-	 * 
-	 * @param title
-	 *            The Title to give to the Style. null will result in title=
-	 *            {@link GridUtil#UNTITLED_RASTER_STYLE_TITLE} or
-	 *            {@link GridUtil#DEFAULT_RASTER_STYLE_TITLE} (if no colorMap is
-	 *            given)
-	 * 
-	 * @return Always a {@link Style} that you can be applyed to a
-	 *         {@link GridCoverage}.
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public static Style createStyleFromColorMap(ColorMap colorMap, String name,
-			String title) {
-		if (colorMap == null)
-			return GridUtil.createDefaultStyle();
-
-		if (name == null)
-			// A colorMap was provided, but no name.
-			name = GridUtil.UNNAMED_RASTER_STYLE_NAME;
-
-		if (title == null)
-			// A colorMap was provided, but no title.
-			title = GridUtil.UNTITLED_RASTER_STYLE_TITLE;
-
-		RasterSymbolizerImpl rasterSymbolizerImpl = new RasterSymbolizerImpl();
-
-		// Entferne alle label informationen
-		clearColorMapLabels(colorMap);
-
-		rasterSymbolizerImpl.setColorMap(colorMap);
-		Symbolizer[] symbolizers = { rasterSymbolizerImpl };
-		RuleImpl ruleImpl = new RuleImpl(symbolizers) {
-		};
-		Rule[] rules = { ruleImpl };
-		FeatureTypeStyleImpl featureTypeStyleImpl = new FeatureTypeStyleImpl(
-				rules) {
-		};
-
-		Style style = STYLE_FACTORY.createStyle();
-		style.setName(name);
-		style.setTitle(title);
-		style.addFeatureTypeStyle(featureTypeStyleImpl);
-		return style;
-	}
-
-	/**
-	 * Removes all label information from the {@link ColorMapEntry}s of the
-	 * given {@link ColorMap}
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public static ColorMap clearColorMapLabels(ColorMap colorMap) {
-		for (ColorMapEntry cme : colorMap.getColorMapEntries()) {
-			cme.setLabel(null);
-		}
-		return colorMap;
-	}
-
-	/**
-	 * Creates a {@link Style} for a {@link Grid} layer from a {@link ColorMap}
-	 * Title will be set to {@link GridUtil#UNTITLED_RASTER_STYLE_TITLE}
-	 * 
-	 * @param colorMap
-	 *            If null, then defaultStyle for Grid will be used
-	 * @param name
-	 *            The name to give to the Style. null will result in name
-	 *            {@link GridUtil#UNTITLED_RASTER_STYLE_TITLE}
-	 * 
-	 * @return Always a Style that you can apply to a {@link GridCoverage}.
-	 *         Style has name {@link GridUtil#DEFAULT_RASTER_STYLE_NAME} if no
-	 *         colormap was provided.
-	 * 
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public static Style createStyleFromColorMap(ColorMap colorMap, String name) {
-		return createStyleFromColorMap(colorMap, name, null);
-	}
-
-	/**
-	 * Loads {@link Style}s from a SLD {@link InputStream}
-	 * 
-	 * @param url
-	 *            {@link URL} to read the SLD from
-	 * 
-	 * @return An {@link Array} of {@link Style}s, can be length==0 if no
-	 *         UserStyles in SLD file. null if file not exists
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public static Style[] loadSLD(URL url) {
-		// LOGGER.debug("Loading styles from URL...");
-		try {
-			return loadSLD(url.openStream());
-		} catch (IOException e) {
-			return null;
-		}
-	}
-
-	/**
-	 * Loads {@link Style}s from a SLD {@link InputStream}
-	 * 
-	 * @param inputStream
-	 *            {@link InputStream} to read the SLD from
-	 * 
-	 * @return An {@link Array} of {@link Style}s, can be length==0. null if
-	 *         file not exists
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public static Style[] loadSLD(InputStream inputStream) {
-		final InputStream inputStream2 = inputStream;
-		if (inputStream2 == null) {
-			return null;
-		}
-
-//		LOGGER.debug("Loading styles from inputStream...");
-
-		SLDParser stylereader;
-		stylereader = new SLDParser(StylingUtil.STYLE_FACTORY);
-		stylereader.setInput(inputStream);
-		Style[] styles = stylereader.readXML();
-
-		if (styles[0] == null) {
-			LOGGER
-					.warn(" ... no Styles recognized in inputStream. Will return empty styles[] array!");
-		} else {
-//			LOGGER.debug(" ... loaded " + styles.length
-//					+ " styles from inputStream, first style's name= "
-//					+ styles[0].getName());
-		}
-
-		// This is the main successful exit form loadSLD
-		return styles;
-	}
-
-	/**
-	 * Loads {@link Style}s from a SLD {@link InputStream} without setting a
-	 * {@link Charset}
-	 * 
-	 * @param inputStream
-	 *            {@link InputStream} to read the SLD from
-	 * 
-	 * @return An {@link Array} of {@link Style}s, can be length==0. null if
-	 *         file not exists
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 * 
-	 * @deprecated
-	 */
-	public static Style[] loadSLDOld(InputStream inputStream) {
-		final InputStream inputStream2 = inputStream;
-		if (inputStream2 == null) {
-			return null;
-		}
-
-		// Reader reader = new UTF8Reader(inputStream2);
-
-		LOGGER.debug("Loading styles from inputStream...");
-
-		SLDParser stylereader;
-		stylereader = new SLDParser(StylingUtil.STYLE_FACTORY, inputStream2);
-		Style[] styles = stylereader.readXML();
-
-		if (styles[0] == null) {
-			LOGGER
-					.warn(" ... no Styles recognized in inputStream. Will return empty styles[] array!");
-		} else {
-			LOGGER.debug(" ... loaded " + styles.length
-					+ " styles from inputStream, first style's name= "
-					+ styles[0].getName());
-		}
-
-		// This is the main successful exit form loadSLD
-		return styles;
-	}
-
-	/**
-	 * Loads {@link Style}s from a SLD {@link File}
-	 * 
-	 * @param sldFile
-	 *            {@link File} to read the SLD from
-	 * 
-	 * @return An {@link Array} of {@link Style}s, can be length==0
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public static Style[] loadSLD(File sldFile) throws FileNotFoundException {
-		LOGGER.debug("Loading styles from File...");
-
-		final Style[] loadedSLD = loadSLD(new FileInputStream(sldFile));
-
-		// TODO Maybe check if names and titles should be set to default
-		// values...
-
-		return loadedSLD;
-	}
-
-	/**
-	 * Saves the {@link Style} to OGC SLD. Overwrites any existing file.
-	 * 
-	 * @param style
-	 *            {@link Style} to save
-	 * @param charset
-	 *            The charset to use for the XML, e.g. <?xml version="1.0"
-	 *            encoding="ISO-8859-1"?>. If null, ISO-8859-1 is used.
-	 * 
-	 * @throws TransformerException
-	 * @throws IOException
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public static final void saveStyleToSLD(Style style, File exportFile,
-			Charset charset) throws TransformerException, IOException {
-		Writer w = null;
-		if (charset != null) {
-			SLDTRANSFORMER.setEncoding(charset);
-		}
-		SLDTRANSFORMER.setIndentation(2);
-		final String xml = SLDTRANSFORMER.transform(style);
-		w = new FileWriter(exportFile);
-		w.write(xml);
-		w.close();
-		LOGGER.info("Saved a Style to " + exportFile + " with charset "
-				+ SLDTRANSFORMER.getEncoding().name());
-	}
-
-	/**
-	 * Saves the {@link Style} to OGC SLD using ISO-8859-1 as charset.
-	 * Overwrites any existing file.
-	 * 
-	 * @param style
-	 *            {@link Style} to save
-	 * 
-	 * @throws TransformerException
-	 * @throws IOException
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public static final void saveStyleToSLD(Style style, File exportFile)
-			throws TransformerException, IOException {
-		saveStyleToSLD(style, exportFile, Charset.forName("ISO-8859-1"));
-	}
-
-	/**
-	 * SLD Rules können die Paramter MinScaleDenominator und MaxScaleDenominator
-	 * enthalten. Dadurch können Elemente für manche Zoom-Stufen deaktiviert
-	 * werden.
-	 * 
-	 * Kommentar: "Sichtbarkeit" bezieht es nicht darauf, ob die Elemente auf
-	 * dem Kartenausschnitt sichtbar sind, sondern um die SLD Regeln, welche das
-	 * Feature evt. nur Scalenabhängig zeichnen.<br/>
-	 * SK 19.6.2009:Bei einem {@link PolygonSymbolizer} zählt nicht der Rand,
-	 * sondern nur ob eine Füllung vorhanden ist! Man kann dann zwar leider
-	 * nicht auf ein Rand eines Polygons ohne Fill klicken, aber dafür kann man
-	 * durch die ungefüllte Fläche klicken.
-	 * 
-	 * @param fc
-	 *            Die zu filternde FeatureCollection. Diese wird nicht
-	 *            verändert.
-	 * @param style
-	 *            Der Style, mit dem die Features gerendert werden (z.b.
-	 *            layer.getStyle() )
-	 * 
-	 * @param scaleDenominator
-	 *            Der aktuelle ScaleDenomitor für den die Sichtbarkeit ermittelt
-	 *            wird.
-	 * 
-	 * @see RendererUtilities.calculateOGCScale
-	 * 
-	 * @return Eine FeatureCollection in welcher nur die Features enthalten
-	 *         sind, welche bei aktuellen Scale mit dem übergebenen Style
-	 *         gerendert werden.
-	 * 
-	 *         TODO Was ist mit raster?!
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public static MemoryFeatureCollection filterSLDVisibleOnly(
-			final FeatureCollection fc, final Style style,
-			final Double scaleDenominator) {
-
-		// Eine im Speicher gehaltene FeatureCollection der sichtbaren
-		final MemoryFeatureCollection fcVisible = new MemoryFeatureCollection(
-				fc.getFeatureType());
-
-		// Prüfen aller Features in der Collection
-		final Iterator<Feature> fcIt = fc.iterator();
-
-		try {
-
-			while (fcIt.hasNext()) {
-				final Feature feature = fcIt.next();
-
-				for (final FeatureTypeStyle fts : style.getFeatureTypeStyles()) {
-					final List<Rule> rules = fts.rules();
-
-					for (final Rule rule : rules) {
-						final double maxScaleDenominator = rule
-								.getMaxScaleDenominator();
-						final double minScaleDenominator = rule
-								.getMinScaleDenominator();
-
-						// 1. Check: Trifft die Rule auf den aktuellen Scale der
-						// JMapPane?
-						if ((minScaleDenominator > scaleDenominator)
-								|| (scaleDenominator > maxScaleDenominator)) {
-							continue;
-						}
-
-						// 2. Check: Eine Rule ist gülrig, aber trifft der
-						// Filter
-						// für dieses Feature?
-						final Filter rFilter = rule.getFilter();
-						if ((rFilter != null) && (!rFilter.evaluate(feature)))
-							continue;
-
-						// 3. Check: Passt einer der Symbolizer dieser Rule zu
-						// dem
-						// Feature? Dieser Check wird in
-						// "real world" meistens klappen, es sei denn, ein
-						// Hansel
-						// gibt einen LineSymbolizer für ein PointLayer an.
-						boolean passt = false;
-						for (final Symbolizer symb : rule.getSymbolizers()) {
-							final Geometry geom = feature.getDefaultGeometry();
-							if ((geom instanceof MultiPoint)
-									|| (geom instanceof com.vividsolutions.jts.geom.Point)) {
-								if (symb instanceof PointSymbolizer) {
-									if (((PointSymbolizer) symb).getGraphic() != null)
-										passt = true;
-									break;
-								}
-							} else if ((geom instanceof MultiLineString)
-									|| (geom instanceof LineString)) {
-								if (symb instanceof LineSymbolizer) {
-									if (((LineSymbolizer) symb).getStroke() != null)
-										passt = true;
-									break;
-								}
-							} else if ((geom instanceof MultiPolygon)
-									|| (geom instanceof Polygon)) {
-								if (symb instanceof PolygonSymbolizer) {
-									if (((PolygonSymbolizer) symb).getFill() != null)
-										passt = true;
-									break;
-								}
-							} else {
-								LOGGER
-										.warn("Unbekannter geom Typ! Gehe von sichbar aus!");
-								passt = true;
-							}
-						}
-						if (!passt)
-							continue;
-
-						// Nun sollte das feature wiklich sichtbar sein
-						fcVisible.add(feature);
-					}
-				}
-			}
-		} catch (final java.lang.IllegalStateException e) {
-			LOGGER.error("Iterating over the features",e);
-			/**
-			 * SK: 14.Apri 2009. It happened a few time to that fcIt.hasNext
-			 * suddenly threw an exception for the "africa countries.shp":
-			 * Exception in thread "AWT-EventQueue-0"
-			 * java.lang.IllegalStateException: ShapeType changed illegally from
-			 * Polygon to Undefined at org.geotools.
-			 * data.shapefile.shp.ShapefileReader.nextRecord(ShapefileReader
-			 * .java:452) at org.geotools.data.shapefile.indexed.
-			 * IndexedShapefileDataStore$Reader
-			 * .next(IndexedShapefileDataStore.java:1272) at
-			 * org.geotools.data.FIDFeatureReader.next(FIDFeatureReader.java:92)
-			 * at org .geotools.data.FilteringFeatureReader.hasNext(
-			 * FilteringFeatureReader .java:125) at
-			 * org.geotools.data.store.FeatureReaderIterator.hasNext(
-			 * FeatureReaderIterator.java:44) at
-			 * schmitzm.geotools.feature.FeatureUtil
-			 * .filterSLDVisibleOnly(FeatureUtil.java:216) *
-			 * 
-			 */
-		}
-
-		// LOGGER.info("filterSLDVisibleOnly removed "+ (fc.size() -
-		// fcVisible.size()) + " features.");
-
-		return fcVisible;
-	}
-
-	/**
-	 * @param style
-	 *            A {@link Style} to search for the first {@link TextSymbolizer}
-	 *            that will be used for the given {@link Feature}.
-	 * 
-	 * @author Stefan A. Krüger
-	 * 
-	 * @return <code>null</code> or the first {@link TextSymbolizer} found in
-	 *         the style that applies to the {@link Feature}.
-	 */
-	public static TextSymbolizer getTextSymbolizer(final Style style,
-			final Feature f) {
-		if (f == null)
-			return null;
-		try {
-			if (style != null) {
-
-				for (final FeatureTypeStyle fts : style.getFeatureTypeStyles()) {
-					for (final Rule r : fts.getRules()) {
-
-						final Filter filter = r.getFilter();
-						//
-						// System.out.println(f);
-						// System.out.println(filter);
-						// System.out.println();
-
-						if (filter != null && (!filter.evaluate(f))) {
-							continue;
-						}
-
-						for (final Symbolizer symb : r.getSymbolizers()) {
-							if (symb instanceof TextSymbolizer) {
-								return (TextSymbolizer) symb;
-							}
-						}
-
-					}
-				}
-
-			}
-
-		} catch (final Exception e) {
-			LOGGER.error("error - filter API stuff?",e);
-			return null;
-		}
-		return null;
-	}
-
-	/**
-	 * @param style
-	 *            A {@link Style} to search for all {@link TextSymbolizer}s . No
-	 *            guarantee, that any one of them will ever be used for any
-	 *            feature (think about filters).
-	 * 
-	 * @author Stefan A. Krüger
-	 * 
-	 * @return {@link List} or all {@link TextSymbolizer}s found in the
-	 *         {@link Style}.
-	 */
-	public static List<TextSymbolizer> getTextSymbolizers(final Style style) {
-		List<TextSymbolizer> results = new ArrayList<TextSymbolizer>();
-		try {
-			if (style != null) {
-
-				for (final FeatureTypeStyle fts : style.getFeatureTypeStyles()) {
-					for (final Rule r : fts.getRules()) {
-						results.addAll(getTextSymbolizers(r.getSymbolizers()));
-					}
-				}
-
-			}
-
-		} catch (final Exception e) {
-			LOGGER.error("error - filter API stuff?",e);
-			return results;
-		}
-		return results;
-	}
-
-	/**
-	 * @param symbolizers
-	 *            List of Symbolizers to search for all {@link TextSymbolizer}s
-	 *            . No guarantee, that any one of them will ever be used for any
-	 *            feature (think about filters).
-	 * 
-	 * @author Stefan A. Krüger
-	 * 
-	 * @return {@link List} or all {@link TextSymbolizer}s found in the given
-	 *         symbolizers.
-	 */
-	public static List<TextSymbolizer> getTextSymbolizers(
-			Symbolizer[] symbolizers) {
-		List<TextSymbolizer> results = new ArrayList<TextSymbolizer>();
-		try {
-			if (symbolizers != null) {
-
-				for (final Symbolizer symb : symbolizers) {
-					if (symb instanceof TextSymbolizer) {
-						results.add((TextSymbolizer) symb);
-					}
-				}
-
-			}
-
-		} catch (final Exception e) {
-			LOGGER.error("error - filter API stuff?",e);
-			return results;
-		}
-		return results;
-	}
-
-	// /**
-	// * Sorts a {@link ColorMap} by its quantity values. This is mentioned in
-	// the
-	// * OGC SLD Definition, page 52:
-	// * <p>
-	// * Quote: For example, a DEM raster giving elevations in meters above sea
-	// * level can be translated to a colored image with a ColorMap. The
-	// quantity
-	// * attributes of a color-map are used for translating between numeric
-	// * matrixes and color rasters and the ColorMap entries should be in order
-	// of
-	// * increasing numeric quantity so that intermediate numeric values can be
-	// * matched to a color (or be interpolated between two colors). Labels may
-	// be
-	// * used for legends or may be used in the future to match character
-	// values.
-	// * Not all systems can support opacity in colormaps. The default opacity
-	// is
-	// * 1.0 (fully opaque). Defaults for quantity and label are
-	// system-dependent.
-	// * </p>
-	// *
-	// * @param colorMap
-	// * {@link ColorMap} to sort by the quantity-field of the
-	// * {@link ColorMapEntry}s
-	// * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	// Kr&uuml;ger</a>
-	// */
-	// public static void sort(RemovableColorMapImpl colorMap) {
-	// ColorMapEntry[] colorMapEntries = colorMap.getColorMapEntries();
-	// SortedMap<Double, ColorMapEntry> tmap = new TreeMap<Double,
-	// ColorMapEntry>();
-	// // Add to a SortedMap
-	// for (ColorMapEntry cme : colorMapEntries) {
-	// tmap.put(getQuantityFromColorMapEntry(cme), cme);
-	// colorMap.removeColorMapEntry(cme);
-	// }
-	// // Recreate ColorMap from sorted quantity values
-	// for (ColorMapEntry cme : tmap.values()) {
-	// colorMap.addColorMapEntry(cme);
-	// }
-	// }
-
-	// /**
-	// * Lets assume that every quantity value is maximally listed once in a
-	// * {@link ColorMap}, then it makes some sense to use it as a key.
-	// *
-	// * @param quantityString
-	// * quantitiy as String
-	// * @return The first colorMap that has the same Quantity ( compared as
-	// * Strings)
-	// *
-	// * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	// Kr&uuml;ger</a>
-	// */
-	// public static ColorMapEntry getColorMapEntryByQuantityString(
-	// ColorMap colorMap, String quantityString) {
-	// for (ColorMapEntry cme : colorMap.getColorMapEntries()) {
-	// if (quantityString.equals(cme.getQuantity().toString()))
-	// return cme;
-	// }
-	// return null;
-	// }
-
-	/**
-	 * Clones a Style by converting it to XML and reading it back in.
-	 * 
-	 * @param style
-	 *            the {@link Style} to be copied.
-	 */
-	public static Style clone(Style style) {
-
-		String xml;
-		try {
-			xml = SLDTRANSFORMER.transform(style);
-
-			SLDParser stylereader;
-			stylereader = new SLDParser(StylingUtil.STYLE_FACTORY,
-					new StringInputStream(xml));
-			Style[] styles = stylereader.readXML();
-
-			return styles[0];
-		} catch (TransformerException e) {
-			ExceptionMonitor.show(null, e);
-			return null;
-		}
-	}
-
-	public static Symbolizer clone(Symbolizer sym) {
-		if (sym == null) {
-			throw new RuntimeException("cant clone null");
-		}
-
-		/**
-		 * Doing some corrections. Otherwise the Symbolizer can not be converted
-		 * to XML
-		 */
-		if (sym instanceof PointSymbolizer) {
-			PointSymbolizer ps = (PointSymbolizer) sym;
-			Graphic graphic = ps.getGraphic();
-
-// That bugfix was needed in 2.4.5 before we patched the StyleFactoryImpl			
-			if (graphic.getSize() instanceof NilExpression) {
-				graphic.setSize(FilterUtil.FILTER_FAC.literal(10.));
-			}
-			
-			
-			try {
-				SLDTRANSFORMER.transform(graphic);
-			} catch (TransformerException e) {
-				LOGGER.error("gr", e);
-			}
-		}
-
-		Style style = STYLE_BUILDER.createStyle(sym); // TODO Mag ich das?
-
-		Filter allwaysTrueFilter = FilterUtil.FILTER_FAC2.equals(
-				FilterUtil.FILTER_FAC2.literal("1"), FilterUtil.FILTER_FAC2
-						.literal("1"));
-
-		style.getFeatureTypeStyles()[0].getRules()[0]
-				.setFilter(allwaysTrueFilter);
-
-		String xml;
-		try {
-			xml = SLDTRANSFORMER.transform(style);
-
-			SLDParser stylereader;
-			stylereader = new SLDParser(StylingUtil.STYLE_FACTORY,
-					new StringInputStream(xml));
-			Style[] styles = stylereader.readXML();
-
-			return (Symbolizer) styles[0].getFeatureTypeStyles()[0].getRules()[0]
-					.getSymbolizers()[0];
-		} catch (TransformerException e) {
-			ExceptionMonitor.show(null, e);
-			return STYLE_FACTORY.createPointSymbolizer(); // TODO Abhängig vom
-			// sym geometry type
-		}
-
-	}
-
-	/**
-	 * Clons a {@link Graphic} element
-	 * 
-	 * @param graphicFill
-	 * @return
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public static Graphic clone(Graphic graphic) {
-		try {
-			PointSymbolizer ps = STYLE_FACTORY.createPointSymbolizer(graphic,
-					"ACHTUNG");
-
-			Style style = STYLE_BUILDER.createStyle(ps);
-
-			final String xml = SLDTRANSFORMER.transform(style);
-
-			SLDParser stylereader;
-			stylereader = new SLDParser(StylingUtil.STYLE_FACTORY,
-					new StringInputStream(xml));
-			Style[] styles = stylereader.readXML();
-
-			PointSymbolizer clonedPs = (PointSymbolizer) styles[0]
-					.getFeatureTypeStyles()[0].getRules()[0].getSymbolizers()[0];
-
-			Graphic clonedG = clonedPs.getGraphic();
-
-			return clonedG;
-
-		} catch (TransformerException e) {
-			LOGGER.error("Cloning a Graphic", e);
-		}
-		return null;
-	}
-
-	/**
-	 * Creates a new {@link BrewerPalette} with only one scheme (which includes
-	 * all colors). The suitablity of the palette is set to "unknown" for all
-	 * viewer types.
-	 * 
-	 * @param name
-	 *            name for the palette (also the description is set to this
-	 *            value)
-	 * @param colors
-	 *            colors for the palette
-	 */
-	public static BrewerPalette createBrewerPalette(String name, Color[] colors)
-			throws IOException {
-		BrewerPalette palette = new BrewerPalette();
-		palette.setColors(colors);
-		palette.setName(name);
-		palette.setDescription(name);
-
-		// set suitability to UNKNOWN for all viewers
-		PaletteSuitability suitability = new PaletteSuitability();
-		suitability.setSuitability(colors.length, new String[] { "?", "?", "?",
-				"?", "?", "?" });
-		palette.setPaletteSuitability(suitability);
-
-		// set the only scheme for the palette (include all colors)
-		int[] schema = new int[colors.length];
-		for (int j = 0; j < schema.length; j++)
-			schema[j] = j;
-		SampleScheme sampleScheme = new SampleScheme();
-		sampleScheme.setSampleScheme(schema.length, schema);
-		palette.setColorScheme(sampleScheme);
-
-		return palette;
-	}
-
-	/**
-	 * @param geoObject
-	 *            {@link GridCoverage2D}, {@link AbstractGridCoverage2DReader},
-	 *            {@link FeatureCollection}, {@link GeometryAttributeType} or
-	 *            {@link FeatureSource}
-	 * 
-	 * @return a {@link Style} that is suitable to identify features of the
-	 *         given type as selected items.
-	 */
-	public static Style createSelectionStyle(Object geoObject) {
-
-		if (geoObject instanceof GridCoverage2D
-				|| geoObject instanceof org.geotools.coverage.grid.io.AbstractGridCoverage2DReader) {
-			// Wenn irgendwann mal selection für raster möglich ist, dann hier
-			// einen schöneren style erstellen.
-			return GridUtil.createDefaultStyle();
-		}
-
-		// We have vector-data. Now let's determine the type...
-		GeometryForm geometryForm = null;
-
-		if (geoObject instanceof FeatureCollection) {
-			geometryForm = FeatureUtil
-					.getGeometryForm((FeatureCollection) geoObject);
-		} else if (geoObject instanceof GeometryAttributeType) {
-			geometryForm = FeatureUtil
-					.getGeometryForm((GeometryAttributeType) geoObject);
-		} else if (geoObject instanceof FeatureSource) {
-			geometryForm = FeatureUtil
-					.getGeometryForm((FeatureSource) geoObject);
-		}
-
-		// /**
-		// * Let's see if we have a cached version of the requested style.
-		// */
-		// if (selectionStyles.containsKey(geometryForm))
-		// return selectionStyles.get(geometryForm);
-
-		Style style = STYLE_FACTORY.createStyle();
-		style.addFeatureTypeStyle(STYLE_FACTORY.createFeatureTypeStyle());
-		Symbolizer[] symbolizers = new Symbolizer[0];
-
-		switch (geometryForm) {
-
-		case POINT:
-			PointSymbolizer ps = STYLE_FACTORY.createPointSymbolizer();
-			ps.setGraphic(SELECTION_GRAPHIC1);
-			symbolizers = LangUtil.extendArray(symbolizers, ps);
-
-			PointSymbolizer ps2 = STYLE_FACTORY.createPointSymbolizer();
-			ps2.setGraphic(SELECTION_GRAPHIC2);
-			symbolizers = LangUtil.extendArray(symbolizers, ps2);
-
-			PointSymbolizer ps3 = STYLE_FACTORY.createPointSymbolizer();
-			ps3.setGraphic(SELECTION_GRAPHIC3);
-			symbolizers = LangUtil.extendArray(symbolizers, ps3);
-
-			break;
-		case POLYGON:
-
-			PolygonSymbolizer polS0 = STYLE_FACTORY.createPolygonSymbolizer();
-
-			Fill SELECTION_FILL0 = STYLE_FACTORY.createFill(STYLE_BUILDER
-					.colorExpression(Color.YELLOW.brighter()));
-
-			polS0.setFill(SELECTION_FILL0);
-			symbolizers = LangUtil.extendArray(symbolizers, polS0);
-
-			PolygonSymbolizer polS = STYLE_FACTORY.createPolygonSymbolizer();
-			polS.setFill(SELECTION_FILL1);
-			symbolizers = LangUtil.extendArray(symbolizers, polS);
-
-		case LINE:
-			LineSymbolizer ls = STYLE_FACTORY.createLineSymbolizer();
-			ls.setStroke(SELECTION_STROKE1);
-			symbolizers = LangUtil.extendArray(symbolizers, ls);
-
-			LineSymbolizer ls2 = STYLE_FACTORY.createLineSymbolizer();
-			ls2.setStroke(SELECTION_STROKE2);
-			symbolizers = LangUtil.extendArray(symbolizers, ls2);
-
-			LineSymbolizer ls3 = STYLE_FACTORY.createLineSymbolizer();
-			ls3.setStroke(SELECTION_STROKE3);
-			symbolizers = LangUtil.extendArray(symbolizers, ls3);
-			break;
-
-		default:
-			throw new IllegalArgumentException("Provide a suitable object.");
-		}
-
-		style.getFeatureTypeStyles()[0].setRules(new Rule[] { STYLE_FACTORY
-				.createRule() });
-		style.getFeatureTypeStyles()[0].getRules()[0]
-				.setSymbolizers(symbolizers);
-
-		// selectionStyles.put(geometryForm, style);
-
-		return style;
-
-	}
-	
-	public static Style createStyleSimple(Object geoObject, Color color, Color color2) {
-		if (geoObject instanceof GridCoverage2D
-				|| geoObject instanceof org.geotools.coverage.grid.io.AbstractGridCoverage2DReader) {
-			// Wenn irgendwann mal selection für raster möglich ist, dann hier
-			// einen schöneren style erstellen.
-			return GridUtil.createDefaultStyle();
-		}
-
-		// We have vector-data. Now let's determine the type...
-		GeometryForm geometryForm = null;
-
-		if (geoObject instanceof FeatureCollection) {
-			geometryForm = FeatureUtil
-					.getGeometryForm((FeatureCollection) geoObject);
-		} else if (geoObject instanceof GeometryAttributeType) {
-			geometryForm = FeatureUtil
-					.getGeometryForm((GeometryAttributeType) geoObject);
-		} else if (geoObject instanceof FeatureSource) {
-			geometryForm = FeatureUtil
-					.getGeometryForm((FeatureSource) geoObject);
-		}
-
-		// /**
-		// * Let's see if we have a cached version of the requested style.
-		// */
-		// if (selectionStyles.containsKey(geometryForm))
-		// return selectionStyles.get(geometryForm);
-
-		Style style = STYLE_FACTORY.createStyle();
-		style.addFeatureTypeStyle(STYLE_FACTORY.createFeatureTypeStyle());
-		Symbolizer[] symbolizers = new Symbolizer[0];
-
-		switch (geometryForm) {
-
-		case POINT:
-			PointSymbolizer ps = STYLE_BUILDER.createPointSymbolizer(STYLE_BUILDER.createGraphic(null, STYLE_BUILDER.createMark("circle"), null));
-			ps.getGraphic().getMarks()[0].setFill(STYLE_BUILDER.createFill(color, 0.5));
-			ps.getGraphic().getMarks()[0].setSize(STYLE_BUILDER.literalExpression(8.));
-			ps.getGraphic().setSize(STYLE_BUILDER.literalExpression(8.));
-			ps.getGraphic().getMarks()[0].setStroke(STYLE_BUILDER.createStroke(color2));
-			symbolizers = LangUtil.extendArray(symbolizers, ps);
-
-			break;
-		case POLYGON:
-			PolygonSymbolizer polS = STYLE_BUILDER.createPolygonSymbolizer(STYLE_BUILDER.createStroke(color2), STYLE_BUILDER.createFill(color));
-			symbolizers = LangUtil.extendArray(symbolizers, polS);
-
-		case LINE:
-			LineSymbolizer ls = STYLE_BUILDER.createLineSymbolizer(STYLE_BUILDER.createStroke(color));
-			symbolizers = LangUtil.extendArray(symbolizers, ls);
-			break;
-
-		default:
-			throw new IllegalArgumentException("Provide a suitable object.");
-		}
-
-		style.getFeatureTypeStyles()[0].setRules(new Rule[] { STYLE_FACTORY
-				.createRule() });
-		style.getFeatureTypeStyles()[0].getRules()[0]
-				.setSymbolizers(symbolizers);
-
-		return style;
-	}
-	
-
-	/**
-	 * Creates a {@link Box} that shows a legend for a list of
-	 * {@link FeatureTypeStyle}s and a targeted featureType
-	 * 
-	 * @param featureType If this a legend for Point, Polygon or Line?
-	 * @param featureTypeStyles The Styles to presen in this legend
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public static Box createLegendPanel(
-			FeatureTypeStyle[] featureTypeStyles, FeatureType featureType) {
-
-		Box box = new Box(BoxLayout.Y_AXIS){
-
-			/**
-			 * Nuetzlich wenn die Componente gedruckt (z.B. wenn ein Screenshot gemacht
-			 * wird) wird. Dann werden wird der Hintergrund auf WEISS gesetzt.
-			 * 
-			 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-			 *         Kr&uuml;ger</a>
-			 */
-			@Override
-			public void print(Graphics g) {
-				final Color orig = getBackground();
-				setBackground(Color.WHITE);
-				// wrap in try/finally so that we always restore the state
-				try {
-					super.print(g);
-				} finally {
-					setBackground(orig);
-				}
-			}
-		};
-
-		for (FeatureTypeStyle ftStyle : featureTypeStyles) {
-
-			// One child-node for every rule
-			Rule[] rules = ftStyle.getRules();
-			for (Rule rule : rules) {
-
-				/**
-				 * Let's not create a hbox for Rules that only contain
-				 * TextSymbolizers
-				 */
-				if (StylingUtil.getTextSymbolizers(rule.getSymbolizers())
-						.size() == rule.getSymbolizers().length)
-					continue;
-
-				Box hbox = new Box( BoxLayout.X_AXIS){
-
-					/**
-					 * Nuetzlich wenn die Componente gedruckt (z.B. wenn ein Screenshot gemacht
-					 * wird) wird. Dann werden wird der Hintergrund auf WEISS gesetzt.
-					 * 
-					 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-					 *         Kr&uuml;ger</a>
-					 */
-					@Override
-					public void print(Graphics g) {
-						final Color orig = getBackground();
-						setBackground(Color.WHITE);
-						// wrap in try/finally so that we always restore the state
-						try {
-							super.print(g);
-						} finally {
-							setBackground(orig);
-						}
-					}
-				};
-
-				/**
-				 * The size of the legend Symbol is dependent on the size of the font.
-				 */
-				final int fontHeight = new JLabel().getFontMetrics(new JLabel().getFont()).getHeight();
-				final Dimension ICON_SIZE = new Dimension(23, fontHeight > 5 ? fontHeight : 5);
-
-
-				// ****************************************************************************
-				// Create the actual icon
-				// ****************************************************************************
-				final BufferedImage imageForRule = LegendIconFeatureRenderer
-						.getInstance().createImageForRule(rule, featureType,
-								ICON_SIZE);
-
-				// LOGGER.debug("Creating a new Legend Image for RUle name =
-				// "+rule.getName());
-
-				ImageIcon legendIcon = new ImageIcon(imageForRule);
-
-				final JLabel iconLabel = new JLabel(legendIcon);
-				hbox.setAlignmentX(0f);
-				hbox.add(iconLabel);
-				hbox.add(Box.createHorizontalStrut(3));
-
-				// ****************************************************************************
-				// The labeltext is read from the SLD. Its either the title
-				// directly, or interpreted as OneLine Code
-				// ****************************************************************************
-				final String rawText = rule.getTitle();
-
-				Translation labelT = new Translation();
-				labelT.fromOneLine(rawText);
-
-				final JLabel classTitleLabel = new JLabel(labelT.toString());
-				hbox.add(classTitleLabel);
-				classTitleLabel.setLabelFor(iconLabel); // Whatever it is good for
-
-				box.add(hbox);
-
-			}
-		}
-
-		return box;
-	}
-
-
-	//
-	// /**
-	// * Doubles the number of palettes by adding the reverse palette to every
-	// * palette. The name of the reverse palette is the name of the original
-	// * palette plus the letter R.
-	// *
-	// * @author SK
-	// * @param palettes The original list of {@link BrewerPalette
-	// BrewerPalettes}
-	// */
-	// public static BrewerPalette[] addReversePalettes(BrewerPalette[]
-	// palettes) {
-	// BrewerPalette[] newPalettes = new BrewerPalette[palettes.length * 2];
-	//
-	// int pos = 0;
-	// for (BrewerPalette bp : palettes) {
-	// newPalettes[pos] = bp;
-	// pos++;
-	// Color[] newColors = new Color[bp.getMaxColors()];
-	//
-	// List<Color> colorList =
-	// java.util.Arrays.asList(bp.getColors(bp.getMaxColors()));
-	// Collections.reverse(colorList);
-	// colorList.toArray(newColors);
-	//
-	// try {
-	// newPalettes[pos] = StylingUtil.createBrewerPalette(bp.getName()
-	// + "R", newColors);
-	// newPalettes[pos].setPaletteSuitability(bp
-	// .getPaletteSuitability());
-	// newPalettes[pos].setDescription(bp.getDescription()+" reversed");
-	// newPalettes[pos].setType(bp.getType());
-	// newPalettes[pos].setColorScheme(bp.getColorScheme());
-	// } catch (IOException e) {
-	// LOGGER.error("",e);
-	// newPalettes[pos] = bp;
-	// }
-	//
-	// pos++;
-	// }
-	//
-	// return newPalettes;
-	// }
-	
-	
-
-	/**
-	 * Replaces the "main" color in a given {@link Symbolizer} element
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public static void replaceSymbolizerColor(Symbolizer symb, Color oldColor,
-			Color newColor) {
-		if (symb == null)
-			return;
-
-		if (symb instanceof PointSymbolizer) {
-			PointSymbolizer ps = (PointSymbolizer) symb;
-			replacePointSymbolizerColor(ps, oldColor, newColor);
-		}
-
-		if (symb instanceof PolygonSymbolizer) {
-			PolygonSymbolizer ps = (PolygonSymbolizer) symb;
-			replacePolygonSymbolizerColor(ps, oldColor, newColor);
-		}
-
-		if (symb instanceof LineSymbolizer) {
-			LineSymbolizer ps = (LineSymbolizer) symb;
-			replaceLineSymbolizerColor(ps, oldColor, newColor);
-		}
-
-	}
-
-	/**
-	 * Replaces the "main" color in a given {@link LineSymbolizer} element
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public static void replaceLineSymbolizerColor(LineSymbolizer ps,
-			Color oldColor, Color newColor) {
-		if (ps == null)
-			return;
-
-		replaceStrokeColor(ps.getStroke(), oldColor, newColor);
-	}
-
-	
-	/**
-	 * Replaces the "main" color in a given {@link PointSymbolizer} element
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public static void replacePointSymbolizerColor(PointSymbolizer ps,
-			Color oldColor, Color newColor) {
-		if (ps == null)
-			return;
-
-		replaceGraphicColor(ps.getGraphic(), oldColor, newColor);
-	}
-
-
-	/**
-	 * Replaces the "main" color in a given {@link PolygonSymbolizer} element
-	 * 
-	 * @param oldColor
-	 * @param newColor
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 * @param ps
-	 */
-	public static void replacePolygonSymbolizerColor(PolygonSymbolizer ps,
-			Color oldColor, Color newColor) {
-		replaceFillColor(ps.getFill(), oldColor, newColor);
-		replaceStrokeColor(ps.getStroke(), oldColor, newColor);
-	}
-
-	/**
-	 * Replaces the "main" color in a given {@link Stroke} element
-	 * @param stroke 
-	 * @param oldColor
-	 * @param newColor
-	 */
-	public static void replaceStrokeColor(Stroke stroke, Color oldColor,
-			Color newColor) {
-		if (stroke == null)
-			return;
-
-		if ((stroke.getColor() != null)
-				&& (StylingUtil.getColorFromExpression(stroke.getColor()).equals(oldColor)))
-			stroke.setColor(StylingUtil.STYLE_BUILDER.colorExpression(newColor));
-
-		replaceGraphicColor(stroke.getGraphicFill(), oldColor, newColor);
-
-		replaceGraphicColor(stroke.getGraphicStroke(), oldColor, newColor);
-
-	}
-
-	/**
-	 * Replaces the "main" color in a given {@link Fill} element
-	 * @param fill
-	 * @param oldColor
-	 * @param newColor
-	 */
-	public static void replaceFillColor(Fill fill, Color oldColor,
-			Color newColor) {
-		if (fill == null)
-			return;
-
-		if ((fill.getColor() != null)
-				&& (getColorFromExpression(fill.getColor()).equals(oldColor)))
-			fill.setColor(STYLE_BUILDER.colorExpression(newColor));
-
-		replaceGraphicColor(fill.getGraphicFill(), oldColor, newColor);
-
-		if ((fill.getBackgroundColor() != null)
-				&& (getColorFromExpression(fill.getBackgroundColor())
-						.equals(oldColor)))
-			fill.setBackgroundColor(STYLE_BUILDER.colorExpression(newColor));
-	}
-
-	/**
-	 * Replaces the "main" color in a given {@link Graphic} element
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public static void replaceGraphicColor(Graphic graphic, Color oldColor,
-			Color newColor) {
-		if (graphic == null)
-			return;
-
-		if ((graphic.getMarks() != null) && (graphic.getMarks().length > 0)) {
-
-			// Checking for Colors in Marks...
-			for (Mark m : graphic.getMarks()) {
-
-				replaceFillColor(m.getFill(), oldColor, newColor);
-
-				replaceStrokeColor(m.getStroke(), oldColor, newColor);
-
-			}
-		}
-	}
-
-
-	/**
-	 * @return the {@link Color} used in the {@link Graphic} or null, if an
-	 *         {@link ExternalGraphic} is used.
-	 * 
-	 * @param graphic
-	 *            If <code>null</code> returns <code>null</code>
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public static Color getGraphicColor(Graphic graphic) {
-		if (graphic == null)
-			return null;
-
-		Color foundColor = null;
-
-		if ((graphic.getMarks() != null) && (graphic.getMarks().length > 0)) {
-
-			// Checking for Colors in Marks...
-			for (Mark m : graphic.getMarks()) {
-
-				if (foundColor == null)
-					foundColor = getFillColor(m.getFill());
-
-				if (foundColor == null)
-					foundColor = getStrokeColor(m.getStroke());
-			}
-
-		}
-
-		return foundColor;
-	}
-
-	/**
-	 * @return the first {@link Color} used in a {@link Stroke}.
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public static Color getStrokeColor(Stroke stroke) {
-		if (stroke == null)
-			return null;
-
-		if (stroke.getColor() != null)
-			return StylingUtil.getColorFromExpression(stroke.getColor());
-
-		if (getGraphicColor(stroke.getGraphicStroke()) != null)
-			return getGraphicColor(stroke.getGraphicStroke());
-
-		if (getGraphicColor(stroke.getGraphicFill()) != null)
-			return getGraphicColor(stroke.getGraphicFill());
-
-		return null;
-	}
-
-	/**
-	 * @return the first {@link Color} used in a {@link Fill}.
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public static Color getFillColor(Fill fill) {
-		if (fill == null)
-			return null;
-
-		Color foundColor = null;
-
-		if (foundColor == null)
-			foundColor = getColorFromExpression(fill.getColor());
-
-		if (foundColor == null)
-			foundColor = getGraphicColor(fill.getGraphicFill());
-
-		if (foundColor == null)
-			foundColor = getColorFromExpression(fill.getBackgroundColor());
-
-		return foundColor;
-	}
-	
-	/**
-	 * @return the first {@link Color} used in a {@link Symbolizer}.
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public static Color getSymbolizerColor(Symbolizer symb) {
-		if (symb == null)
-			return null;
-
-		if (symb instanceof PointSymbolizer) {
-			PointSymbolizer ps = (PointSymbolizer) symb;
-			return getPointSymbolizerColor(ps);
-		}
-
-		if (symb instanceof PolygonSymbolizer) {
-			PolygonSymbolizer ps = (PolygonSymbolizer) symb;
-			return getPolygonSymbolizerColor(ps);
-		}
-
-		if (symb instanceof LineSymbolizer) {
-			LineSymbolizer ps = (LineSymbolizer) symb;
-			return getLineSymbolizerColor(ps);
-		}
-
-		return null;
-	}
-
-	
-	/**
-	 * @return the first {@link Color} used in a {@link LineSymbolizer}.
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public static Color getLineSymbolizerColor(LineSymbolizer ps) {
-		if (ps == null)
-			return null;
-
-		Color foundColor = null;
-
-		if (foundColor == null)
-			foundColor = getStrokeColor(ps.getStroke());
-
-		return foundColor;
-	}
-
-
-	/**
-	 * @return the first {@link Color} used in a {@link PolygonSymbolizer}.
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public static Color getPolygonSymbolizerColor(PolygonSymbolizer ps) {
-		if (ps == null)
-			return null;
-
-		Color foundColor = null;
-
-		if (foundColor == null)
-			foundColor = getFillColor(ps.getFill());
-
-		if (foundColor == null)
-			foundColor = getStrokeColor(ps.getStroke());
-
-		return foundColor;
-	}
-
-
-	/**
-	 * @return the first {@link Color} used in a {@link PointSymbolizer}.
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public static Color getPointSymbolizerColor(PointSymbolizer ps) {
-		if (ps == null)
-			return null;
-
-		return getGraphicColor(ps.getGraphic());
-	}
-
-
-	/***************************************************************************
-	 * Copies all Values from one {@link TextSymbolizer} to another
-	 * {@link TextSymbolizer}
-	 * 
-	 * @param from {@link TextSymbolizer} source
-	 * @param to {@link TextSymbolizer} target. May not be <code>null</code>.
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public static void copyAllValues(final TextSymbolizer from,
-			final TextSymbolizer to) {
-		to.setLabel(from.getLabel());
-		
-		final FilterFactory2 ff2 = FeatureUtil.FILTER_FACTORY2;
-		
-		to.getFonts()[0].setFontFamily(ff2.literal(from.getFonts()[0]
-				.getFontFamily().toString()));
-		to.getFonts()[0].setFontSize(ff2.literal(from.getFonts()[0]
-				.getFontSize().toString()));
-		to.getFonts()[0].setFontWeight(ff2.literal(from.getFonts()[0]
-				.getFontWeight().toString()));
-		to.getFonts()[0].setFontStyle(ff2.literal(from.getFonts()[0]
-				.getFontStyle().toString()));
-	}
-
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.geotools.styling;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Writer;
+import java.lang.reflect.Array;
+import java.net.URL;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import javax.swing.Box;
+import javax.swing.BoxLayout;
+import javax.swing.ImageIcon;
+import javax.swing.JLabel;
+import javax.units.Unit;
+import javax.xml.transform.TransformerException;
+
+import org.apache.log4j.Logger;
+import org.geotools.brewer.color.BrewerPalette;
+import org.geotools.brewer.color.PaletteSuitability;
+import org.geotools.brewer.color.SampleScheme;
+import org.geotools.coverage.Category;
+import org.geotools.coverage.GridSampleDimension;
+import org.geotools.coverage.grid.GridCoverage2D;
+import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader;
+import org.geotools.data.FeatureSource;
+import org.geotools.data.memory.MemoryFeatureCollection;
+import org.geotools.factory.CommonFactoryFinder;
+import org.geotools.factory.GeoTools;
+import org.geotools.feature.Feature;
+import org.geotools.feature.FeatureCollection;
+import org.geotools.feature.FeatureType;
+import org.geotools.feature.GeometryAttributeType;
+import org.geotools.filter.ConstantExpression;
+import org.geotools.gui.swing.ExceptionMonitor;
+import org.geotools.renderer.lite.RendererUtilities;
+import org.geotools.resources.i18n.Vocabulary;
+import org.geotools.resources.i18n.VocabularyKeys;
+import org.geotools.styling.ColorMap;
+import org.geotools.styling.ColorMapEntry;
+import org.geotools.styling.ColorMapEntryImpl;
+import org.geotools.styling.ColorMapImpl;
+import org.geotools.styling.ExternalGraphic;
+import org.geotools.styling.FeatureTypeStyle;
+import org.geotools.styling.FeatureTypeStyleImpl;
+import org.geotools.styling.Fill;
+import org.geotools.styling.Graphic;
+import org.geotools.styling.LineSymbolizer;
+import org.geotools.styling.Mark;
+import org.geotools.styling.PointSymbolizer;
+import org.geotools.styling.PolygonSymbolizer;
+import org.geotools.styling.RasterSymbolizer;
+import org.geotools.styling.RasterSymbolizerImpl;
+import org.geotools.styling.Rule;
+import org.geotools.styling.RuleImpl;
+import org.geotools.styling.SLDParser;
+import org.geotools.styling.SLDTransformer;
+import org.geotools.styling.Stroke;
+import org.geotools.styling.Style;
+import org.geotools.styling.StyleBuilder;
+import org.geotools.styling.StyleFactory;
+import org.geotools.styling.Symbolizer;
+import org.geotools.styling.TextSymbolizer;
+import org.geotools.util.NumberRange;
+import org.jdom.Element;
+import org.jdom.output.XMLOutputter;
+import org.opengis.coverage.grid.Grid;
+import org.opengis.coverage.grid.GridCoverage;
+import org.opengis.filter.Filter;
+import org.opengis.filter.FilterFactory2;
+import org.opengis.filter.expression.Expression;
+import org.opengis.filter.expression.Literal;
+import org.opengis.filter.expression.NilExpression;
+
+import schmitzm.geotools.FilterUtil;
+import schmitzm.geotools.feature.FeatureUtil;
+import schmitzm.geotools.feature.FeatureUtil.GeometryForm;
+import schmitzm.geotools.grid.GridUtil;
+import schmitzm.lang.LangUtil;
+import skrueger.geotools.LegendIconFeatureRenderer;
+import skrueger.i8n.Translation;
+
+import com.sun.xml.bind.StringInputStream;
+import com.vividsolutions.jts.geom.Geometry;
+import com.vividsolutions.jts.geom.LineString;
+import com.vividsolutions.jts.geom.MultiLineString;
+import com.vividsolutions.jts.geom.MultiPoint;
+import com.vividsolutions.jts.geom.MultiPolygon;
+import com.vividsolutions.jts.geom.Polygon;
+
+/**
+ * Diese Klasse enthaelt Hilfsfunktionen zum GeoTools-Styling
+ * 
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *         (University of Bonn/Germany)
+ * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
+ * 
+ * @version 1.1
+ */
+public class StylingUtil {
+	private static final Logger LOGGER = Logger.getLogger(StylingUtil.class);
+	/** Transparente Farbe */
+	public static final Color TRANSPARENT_COLOR = new Color(0, 0, 0, 0);
+
+	/**
+	 * Standard-Instanz eines {@link StyleBuilder}.
+	 * 
+	 * @Deprecated Bitte nicht benutzen. Ich habe schlechte Efahrungen damit.
+	 *             Zumindest uin 2.4.
+	 */
+	public static final StyleBuilder STYLE_BUILDER = new StyleBuilder();
+
+	/** Standard-Instanz eines {@link SLDTransformer}. */
+	public final static SLDTransformer SLDTRANSFORMER = new SLDTransformer();
+
+	/**
+	 * Standard-Instanz eines {@link StyleBuilder}.
+	 * 
+	 * @deprecated wurde ersetzt durch {@link #STYLE_BUILDER}
+	 */
+	public static final StyleBuilder builder = STYLE_BUILDER;
+
+	/** Standard-Instanz einer {@link StyleFactory} */
+	public static final StyleFactory STYLE_FACTORY = CommonFactoryFinder
+			.getStyleFactory(GeoTools.getDefaultHints());
+
+	/**
+	 * Standard-Instanz einer {@link StyleFactory}
+	 * 
+	 * @deprecated wurde ersetzt durch {@link #STYLE_FACTORY}
+	 */
+	public static final StyleFactory styleFactory = STYLE_FACTORY;
+
+	/**
+	 * TODO SK The following constants are used to speed up
+	 * {@link #createSelectionStyle(Object)}. I will "redo" them soon and also
+	 * document them. This is still under construction. TODO SK
+	 */
+
+	static final Literal size0 = FeatureUtil.FILTER_FACTORY2.literal(13);
+	static final Literal size1 = FeatureUtil.FILTER_FACTORY2.literal(9);
+	static final Literal size2 = FeatureUtil.FILTER_FACTORY2.literal(7);
+	static final Literal size3 = FeatureUtil.FILTER_FACTORY2.literal(3);
+	static final Literal zeroLit = FeatureUtil.FILTER_FACTORY2.literal(0);
+
+	// static final Stroke SELECTION_STROKE1 =
+	// STYLE_FACTORY.createStroke(STYLE_BUILDER.colorExpression(Color.YELLOW),
+	// size2);
+
+	static final Stroke SELECTION_STROKE1 = STYLE_FACTORY.createStroke(
+			STYLE_BUILDER.colorExpression(Color.YELLOW.brighter()),
+			FeatureUtil.FILTER_FACTORY2.literal(4), FeatureUtil.FILTER_FACTORY2
+					.literal(1.), FeatureUtil.FILTER_FACTORY.literal("round"),
+			FeatureUtil.FILTER_FACTORY.literal("round"), new float[0],
+			FeatureUtil.FILTER_FACTORY2.literal(0), null, null);
+
+	static final Stroke SELECTION_STROKE2 = STYLE_FACTORY.createStroke(
+			STYLE_BUILDER.colorExpression(Color.BLACK),
+			FeatureUtil.FILTER_FACTORY2.literal(1.5),
+			FeatureUtil.FILTER_FACTORY2.literal(1.), FeatureUtil.FILTER_FACTORY
+					.literal("round"), FeatureUtil.FILTER_FACTORY
+					.literal("round"), new float[] { 3f, 3f },
+			FeatureUtil.FILTER_FACTORY2.literal(0), null, null);
+
+	static final Stroke SELECTION_STROKE3 = STYLE_FACTORY.createStroke(
+			STYLE_BUILDER.colorExpression(Color.WHITE),
+			FeatureUtil.FILTER_FACTORY2.literal(1.5),
+			FeatureUtil.FILTER_FACTORY2.literal(1.), FeatureUtil.FILTER_FACTORY
+					.literal("round"), FeatureUtil.FILTER_FACTORY
+					.literal("round"), new float[] { 3f, 3f },
+			FeatureUtil.FILTER_FACTORY2.literal(3), null, null);
+
+	static final Graphic SELECTION_GRAPHIC1 = STYLE_FACTORY.createGraphic(
+			new ExternalGraphic[0], new Mark[] { STYLE_FACTORY.createMark(
+					FeatureUtil.FILTER_FACTORY2.literal("square"), null,
+					STYLE_FACTORY.createFill(STYLE_BUILDER
+							.colorExpression(Color.WHITE)), size1, zeroLit) },
+			new org.geotools.styling.Symbol[0], FeatureUtil.FILTER_FACTORY2
+					.literal(1), size1, zeroLit);
+
+	static final Graphic SELECTION_GRAPHIC2 = STYLE_FACTORY.createGraphic(
+			new ExternalGraphic[0], new Mark[] { STYLE_FACTORY.createMark(
+					FeatureUtil.FILTER_FACTORY2.literal("circle"), null,
+					STYLE_FACTORY.createFill(STYLE_BUILDER
+							.colorExpression(Color.BLACK)), size2, zeroLit) },
+			new org.geotools.styling.Symbol[0], FeatureUtil.FILTER_FACTORY2
+					.literal(1), size2, zeroLit);
+
+	static final Graphic SELECTION_GRAPHIC3 = STYLE_FACTORY.createGraphic(
+			new ExternalGraphic[0], new Mark[] { STYLE_FACTORY.createMark(
+					FeatureUtil.FILTER_FACTORY2.literal("circle"), null,
+					STYLE_FACTORY.createFill(STYLE_BUILDER
+							.colorExpression(Color.YELLOW.brighter())), size3,
+					zeroLit) }, new org.geotools.styling.Symbol[0],
+			FeatureUtil.FILTER_FACTORY2.literal(1), size3, zeroLit);
+	static final Fill SELECTION_FILL1 = STYLE_FACTORY.createFill(STYLE_BUILDER
+			.colorExpression(Color.RED), null, FeatureUtil.FILTER_FACTORY2
+			.literal(1), STYLE_FACTORY.createGraphic(new ExternalGraphic[0],
+			new Mark[] { STYLE_FACTORY.createMark(FeatureUtil.FILTER_FACTORY2
+					.literal("circle"), null, STYLE_FACTORY
+					.createFill(STYLE_BUILDER.colorExpression(Color.RED)),
+					size3, zeroLit) }, new org.geotools.styling.Symbol[0],
+			FeatureUtil.FILTER_FACTORY2.literal(1), size3, zeroLit));
+
+	// /**
+	// * Up to three {@link Style styles} suitable to present selected {@link
+	// Feature features} are cached here. (SK)
+	// */
+	// private static Map<GeometryForm,Style> selectionStyles = new
+	// HashMap<GeometryForm, Style>();
+
+	/**
+	 * Erstellt einen Default-Style fuer ein Geo-Objekt.
+	 * 
+	 * @param object
+	 *            {@link GridCoverage2D},
+	 *            {@link org.geotools.coverage.grid.io.AbstractGridCoverage2DReader}
+	 *            oder {@link FeatureCollection}
+	 * @return {@code null} falls kein Style generiert werden kann
+	 * 
+	 */
+	public static Style createDefaultStyle(Object object) {
+		Style style = STYLE_FACTORY.createStyle(); // SK.. nicer default than
+		// null !
+
+		if (object instanceof GridCoverage2D
+				|| object instanceof org.geotools.coverage.grid.io.AbstractGridCoverage2DReader)
+			style = GridUtil.createDefaultStyle();
+
+		if (object instanceof FeatureCollection)
+			style = FeatureUtil.createDefaultStyle((FeatureCollection) object);
+
+		// SK.cb
+		if (object instanceof GeometryAttributeType)
+			style = FeatureUtil
+					.createDefaultStyle((GeometryAttributeType) object);
+
+		if (object instanceof FeatureSource)
+			style = FeatureUtil.createDefaultStyle(((FeatureSource) object)
+					.getSchema().getDefaultGeometry());
+		// SK.ce
+
+		return style;
+	}
+
+	/**
+	 * Erzeugt eine {@link Category} fuer die NoData-Werte transparent
+	 * dargestellt werden.
+	 * 
+	 * @param geoValue
+	 *            Geo-Wert, der NoData repraesentiert
+	 */
+	public static Category createNoDataCategory(double geoValue) {
+		return createNoDataCategory(0, geoValue);
+	}
+
+	/**
+	 * Erzeugt eine {@link Category} fuer die NoData-Werte transparent
+	 * dargestellt werden.
+	 * 
+	 * @param value
+	 *            Sample-Wert der Category
+	 * @param geoValue
+	 *            Geo-Wert, der NoData repraesentiert
+	 */
+	public static Category createNoDataCategory(int value, double geoValue) {
+		return new Category(Vocabulary
+				.formatInternational(VocabularyKeys.NODATA),
+				new Color[] { new Color(0, 0, 0, 0) }, new NumberRange(value,
+						value), new NumberRange(geoValue, geoValue));
+	}
+
+	/**
+	 * Erzeugt eine {@link GridSampleDimension} aus einer {@link ColorMap}.
+	 * 
+	 * @param name
+	 *            Name fuer die {@link GridSampleDimension}
+	 * @param colorMap
+	 *            fuer jeden Eintrag der {@link ColorMap} wird eine
+	 *            {@link Category} erzeugt
+	 * @param noDataValues
+	 *            Werte fuer die zusaetzliche {@link Category Categorys}
+	 *            erstellt werden, welche die transparent dargestellt werden
+	 *            (wenn {@code null} wird keine zusaetzliche {@link Category}
+	 *            erstellt)
+	 * @param unit
+	 *            Einheit der Werte in der {@link GridSampleDimension} (kann
+	 *            {@code null} sein)
+	 */
+	public static GridSampleDimension createDiscreteGridSampleDimension(
+			String name, ColorMap colorMap, double[] noDataValues, Unit unit) {
+		if (colorMap.getColorMapEntries().length == 0)
+			return null;
+
+		SortedMap<Integer, Category> categories = new TreeMap<Integer, Category>();
+		if (noDataValues == null)
+			noDataValues = new double[0];
+
+		// Create a (discrete) Category for each ColorMapEntry
+		int colorMapMin = Integer.MAX_VALUE;
+		int colorMapMax = Integer.MIN_VALUE;
+		for (ColorMapEntry cme : colorMap.getColorMapEntries()) {
+			String label = cme.getLabel();
+			Color color = getColorFromColorMapEntry(cme);
+			double value = getQuantityFromColorMapEntry(cme);
+			int intValue = (int) Math.round(value);
+			colorMapMin = Math.min(colorMapMin, intValue);
+			colorMapMax = Math.max(colorMapMax, intValue);
+			// if ( label == null || label.trim().equals("") )
+			// label = String.valueOf(intValue);
+			if (label == null)
+				label = "";
+			categories.put(intValue, new Category(label, new Color[] { color },
+					new NumberRange(intValue, intValue), new NumberRange(
+							intValue, intValue)));
+		}
+
+		// If NoData-Value is set, create an additional Category
+		for (double noDataValue : noDataValues) {
+			int value = categories.lastKey() + 10; // value not already used
+			categories.put(value, createNoDataCategory(value, noDataValue));
+			colorMapMin = Math.min(colorMapMin, (int) noDataValue);
+			colorMapMax = Math.max(colorMapMax, (int) noDataValue);
+		}
+
+		// Declare "all" values smaller/greater the color map values
+		// automatically as NoData
+		// int colorMapRange = colorMapMax - colorMapMin;
+		// double lowerStart = colorMapMin - 10000*colorMapRange;
+		// double higherEnd = colorMapMax + 10000*colorMapRange;
+		final int lowerStart = Integer.MIN_VALUE;
+		final int higherEnd = Integer.MAX_VALUE;
+		categories.put(colorMapMax + 10, new Category("_autoNoData1_",
+				new Color[] { new Color(0, 0, 0, 0) }, new NumberRange(
+						colorMapMax + 1, colorMapMax + 2), new NumberRange(
+						colorMapMax + 1, higherEnd)));
+		if (colorMapMin < colorMapMax)
+			categories.put(colorMapMin - 10, new Category(
+					"_autoNoData2_",
+					new Color[] { new Color(0, 0, 0, 0) },
+					// new NumberRange(colorMapMin-2, colorMapMin-1), //
+					// logischer, aber klappt nicht!?
+					new NumberRange(colorMapMax + 3, colorMapMax + 4),
+					new NumberRange(lowerStart, colorMapMin - 1)));
+
+		// Create the GridSampleDimension
+		GridSampleDimension gsd = new GridSampleDimension(name, categories
+				.values().toArray(new Category[0]), unit).geophysics(true);
+
+		for (Category c : (List<Category>) gsd.getCategories())
+			LOGGER.debug(c.toString());
+
+		return gsd;
+	}
+
+	/**
+	 * Liefert die Farbpalette zu einem Style, wenn der Style aus einem
+	 * {@link RasterSymbolizer} erzeugt wurde.
+	 * 
+	 * @param style
+	 *            Style Wenn <code>null</code>, dann wird style auf
+	 *            {@link GridUtil}.createDefaultStyle() gesetzt
+	 * @return <code>null</code> wenn der Style nicht auf einem
+	 *         {@link RasterSymbolizer} basiert.
+	 */
+	public static ColorMap getColorMapFromStyle(Style style) {
+
+		if (style == null)
+			style = GridUtil.createDefaultStyle();
+
+		FeatureTypeStyle[] fts = style.getFeatureTypeStyles();
+		if (fts == null || fts.length == 0)
+			return null;
+		Rule[] rule = fts[0].getRules();
+		if (rule == null || rule.length == 0)
+			return null;
+		Symbolizer[] symb = rule[0].getSymbolizers();
+		if (symb == null || symb.length == 0
+				|| !(symb[0] instanceof RasterSymbolizer))
+			return null;
+		return ((RasterSymbolizer) symb[0]).getColorMap();
+
+	}
+
+	/**
+	 * Ermittelt fuer einen Wert den {@link ColorMapEntry} aus einer
+	 * {@link ColorMap}.
+	 * 
+	 * @param value
+	 *            Wert
+	 * @return {@code null}, wenn in der {@link ColorMap} kein expliziter
+	 *         Eintrag fuer den Wert hinterlegt ist
+	 */
+	public static ColorMapEntry findColorMapEntry(ColorMap colorMap,
+			double value) {
+		for (ColorMapEntry entry : colorMap.getColorMapEntries())
+			if (value == getQuantityFromColorMapEntry(entry))
+				return entry;
+		return null;
+	}
+
+	/**
+	 * Kopiert eine {@link ColorMap}.
+	 * 
+	 * @return <code>null</code> wenn die uebergebene ColorMap <code>null</code>
+	 *         ist
+	 */
+	public static ColorMap cloneColorMap(ColorMap colorMap) {
+		if (colorMap == null)
+			return null;
+		ColorMapEntry[] entry = colorMap.getColorMapEntries();
+		ColorMap newColorMap = new ColorMapImpl();
+		newColorMap.setType(colorMap.getType()); // Hat noch keinen Effekt in
+		// 2.3.2, aber dennoch, SK
+		for (int i = 0; i < entry.length; i++)
+			newColorMap.addColorMapEntry(cloneColorMapEntry(entry[i]));
+		return newColorMap;
+	}
+
+	/**
+	 * Prueft, ob zwei {@link ColorMap}-Instanzen gleich sind.
+	 * 
+	 * @param cm1
+	 *            eine Farbpalette
+	 * @param cm2
+	 *            eine andere Farbpalette
+	 */
+	public static boolean colorMapsEqual(ColorMap cm1, ColorMap cm2) {
+		if (cm1 == null ^ cm2 == null)
+			return false;
+		if (cm1 == cm2)
+			return true;
+
+		ColorMapEntry[] cme1 = cm1.getColorMapEntries();
+		ColorMapEntry[] cme2 = cm2.getColorMapEntries();
+		if (cme1.length != cme2.length)
+			return false;
+
+		// Farbpaletten-Eintraege muessen gleich sein und in gleicher
+		// Reihenfolge vorliegen!
+		for (int i = 0; i < cme1.length; i++)
+			if (!colorMapEntriesEqual(cme1[i], cme2[i]))
+				return false;
+		return true;
+	}
+
+	/**
+	 * Prueft, ob zwei {@link ColorMapEntry}-Instanzen gleich sind. Dies ist der
+	 * Fall, wenn ihnen der gleiche Wert, die gleiche Farbe, die gleiche
+	 * Transparenz und das gleiche Label zugeordnet ist.
+	 * 
+	 * @param cme1
+	 *            ein Farbpaletten-Eintrag
+	 * @param cme2
+	 *            ein anderer Farbpaletten-Eintrag
+	 */
+	public static boolean colorMapEntriesEqual(ColorMapEntry cme1,
+			ColorMapEntry cme2) {
+		if (cme1 == null ^ cme2 == null)
+			return false;
+		if (cme1 == cme2)
+			return true;
+
+		// Label auf Gleichheit testen
+		if (cme1.getLabel() == null ^ cme2.getLabel() == null || cme1 != null
+				&& !cme1.getLabel().equals(cme2.getLabel()))
+			return false;
+		// Farbe auf Gleichheit testen
+		Color col1 = getColorFromColorMapEntry(cme1);
+		Color col2 = getColorFromColorMapEntry(cme2);
+		if (col1 == null ^ col2 == null || col1 != null && !col1.equals(col2))
+			return false;
+		// Wert auf Gleichheit testen
+		Double quan1 = getQuantityFromColorMapEntry(cme1);
+		Double quan2 = getQuantityFromColorMapEntry(cme2);
+		if (quan1 == null ^ quan2 == null || quan1 != null
+				&& !quan1.equals(quan2))
+			return false;
+		// Transparenz auf Gleichheit testen
+		Double op1 = getOpacityFromColorMapEntry(cme1);
+		Double op2 = getOpacityFromColorMapEntry(cme2);
+		if (op1 == null ^ op2 == null || op1 != null && !op1.equals(op2))
+			return false;
+
+		return true;
+	}
+
+	/**
+	 * Erzeugt einen {@link ColorMapEntry}.
+	 * 
+	 * @param label
+	 *            Label fuer den Farbpaletten-Eintrag
+	 * @param quantity
+	 *            Wert fuer den Farbpaletten-Eintrag
+	 * @param color
+	 *            Farbe fuer den Farbpaletten-Eintrag
+	 * @param opacity
+	 *            Transparenz fuer die Farbe des Farbpaletten-Eintrag
+	 */
+	public static ColorMapEntry createColorMapEntry(String label,
+			Double quantity, Color color, double opacity) {
+		ColorMapEntry newEntry = new ColorMapEntryImpl();
+		try {
+			newEntry.setLabel(label);
+			newEntry.setColor(STYLE_BUILDER.colorExpression(color));
+			newEntry.setOpacity(STYLE_BUILDER.literalExpression(opacity));
+			newEntry.setQuantity(STYLE_BUILDER.literalExpression(quantity));
+		} catch (Exception err) {
+		}
+		return newEntry;
+	}
+
+	/**
+	 * Kopiert einen {@link ColorMapEntry}.
+	 * 
+	 * @return <code>null</code> wenn der uebergebene ColorMapEntry
+	 *         <code>null</code> ist
+	 */
+	public static ColorMapEntry cloneColorMapEntry(ColorMapEntry colorMapEntry) {
+		if (colorMapEntry == null)
+			return null;
+
+		return createColorMapEntry(colorMapEntry.getLabel(),
+				getQuantityFromColorMapEntry(colorMapEntry),
+				getColorFromColorMapEntry(colorMapEntry),
+				getOpacityFromColorMapEntry(colorMapEntry));
+	}
+
+	/**
+	 * Liefert den Wert eines Farbpaletten-Eintrag.
+	 * 
+	 * @param expression
+	 *            Expression, die einen String oder einen Double liefert
+	 * @return {@code null}, wenn <code>null</code> uebergeben wird
+	 */
+	public static Double getQuantityFromExpression(Expression expression) {
+		// gt2-2.3.4:
+		// if ( expression == null || expression.getValue(null) == null )
+		// return null
+		// Object exprValue = evaluate.getValue(null);
+		// gt2-2.3.4:
+		if (expression == null || expression.evaluate(null) == null)
+			return null;
+		Object exprValue = expression.evaluate(null);
+
+		return (exprValue instanceof String) ? Double
+				.valueOf((String) exprValue) : ((Number) exprValue)
+				.doubleValue();
+	}
+
+	/**
+	 * Liefert den Wert eines Farbpaletten-Eintrag.
+	 * 
+	 * @param entry
+	 *            Farbpaletten-Eintrag
+	 * @return {@code null}, wenn <code>null</code> uebergeben wird
+	 */
+	public static Double getQuantityFromColorMapEntry(ColorMapEntry entry) {
+		if (entry == null)
+			return null;
+		return getQuantityFromExpression(entry.getQuantity());
+	}
+
+	/**
+	 * Setzt den Wert eines Farbpaletten-Eintrag.
+	 * 
+	 * @param entry
+	 *            Farbpaletten-Eintrag
+	 * @param quantity
+	 *            neuer Wert
+	 */
+	public static void setQuantityForColorMapEntry(ColorMapEntry entry,
+			double quantity) {
+		if (entry != null)
+			entry.setQuantity(STYLE_BUILDER.literalExpression(quantity));
+	}
+
+	/**
+	 * Liefert die Transparenz eines Farbpaletten-Eintrag.
+	 * 
+	 * @param expression
+	 *            Expression, die einen String oder einen Double liefert
+	 * @return 1.0, wenn <code>null</code> uebergeben wird
+	 */
+	public static Double getOpacityFromExpression(Expression expression) {
+		// gt2-2.3.4:
+		// if ( expression == null || expression.getValue(null) == null )
+		// return 1.0
+		// Object exprValue = evaluate.getValue(null);
+		// gt2-2.3.4:
+		if (expression == null || expression.evaluate(null) == null)
+			return 1.0;
+		Object exprValue = expression.evaluate(null);
+
+		return (exprValue instanceof String) ? Double
+				.valueOf((String) exprValue) : ((Number) exprValue)
+				.doubleValue();
+	}
+
+	/**
+	 * Liefert die Transparenz eines Farbpaletten-Eintrag.
+	 * 
+	 * @param entry
+	 *            Farbpaletten-Eintrag
+	 * @return 1.0, wenn <code>null</code> uebergeben wird
+	 */
+	public static Double getOpacityFromColorMapEntry(ColorMapEntry entry) {
+		if (entry == null)
+			return 1.0;
+		return getOpacityFromExpression(entry.getOpacity());
+	}
+
+	/**
+	 * Setzt die Transparenz eines Farbpaletten-Eintrag.
+	 * 
+	 * @param entry
+	 *            Farbpaletten-Eintrag
+	 * @param opacity
+	 *            Transparenzwert
+	 */
+	public static void setOpacityForColorMapEntry(ColorMapEntry entry,
+			double opacity) {
+		if (entry != null)
+			entry.setOpacity(STYLE_BUILDER.literalExpression(opacity));
+	}
+
+	/**
+	 * Liefert die Farbe eines Farbpaletten-Eintrag.
+	 * 
+	 * @param expression
+	 *            Expression, die einen String liefert
+	 */
+	public static Color getColorFromExpression(Expression expression) {
+		if (expression == null)
+			return null;
+
+		if (expression instanceof ConstantExpression) {
+			ConstantExpression a = (ConstantExpression) expression;
+			Object obj = a.getValue();
+			if (obj instanceof Color) {
+				return (Color) obj;
+			}
+		}
+
+		return Color.decode(expression.toString());
+
+		// Old way Martin did it:
+		// return Color.decode((String) expression.evaluate(null));
+
+	}
+
+	/**
+	 * Liefert die Farbe eines Farbpaletten-Eintrag.
+	 * 
+	 * @param entry
+	 *            Farbpaletten-Eintrag
+	 */
+	public static Color getColorFromColorMapEntry(ColorMapEntry entry) {
+		// if ( entry == null || entry.getColor() == null ||
+		// entry.getColor().getValue(null) == null ) // gt2-2.3.4
+		if (entry == null || entry.getColor() == null
+				|| entry.getColor().evaluate(null) == null) // gt2-2-4-2
+			return null;
+
+		// // Transparenz
+		// Double opacity = getOpacityFromColorMapEntry(entry);
+
+		return getColorFromExpression(entry.getColor());
+	}
+
+	/**
+	 * Setzt die Farbe eines Farbpaletten-Eintrag.
+	 * 
+	 * @param entry
+	 *            Farbpaletten-Eintrag
+	 * @param color
+	 *            eine Farbe
+	 */
+	public static void setColorForColorMapEntry(ColorMapEntry entry, Color color) {
+		if (entry != null)
+			entry.setColor(STYLE_BUILDER.colorExpression(color));
+	}
+
+	/**
+	 * Erzeugt einen {@link Style} aus einem {@linkplain Element JDOM-Element},
+	 * des eine SLD-Definition enthaelt
+	 * 
+	 * @param element
+	 *            Element mit SLD-Definition
+	 */
+	public static Style createStyleFromSLD(Element element) {
+		String xmlDefinition = new XMLOutputter().outputString(element);
+		Style[] style = loadSLD(new ByteArrayInputStream(xmlDefinition
+				.getBytes()));
+		return style == null || style.length == 0 ? null : style[0];
+	}
+
+	/**
+	 * Creates a {@link Style} for a {@link Grid} layer from a {@link ColorMap}
+	 * 
+	 * @param colorMap
+	 *            If null, then defaultStyle for Grid will be used
+	 * @param name
+	 *            The name to give to the Style. null will result in name=
+	 *            {@link GridUtil#UNNAMED_RASTER_STYLE_NAME} or
+	 *            GridUtil#DEFAULT_RASTER_STYLE_NAME} (if no colorMap is given).
+	 * 
+	 * @param title
+	 *            The Title to give to the Style. null will result in title=
+	 *            {@link GridUtil#UNTITLED_RASTER_STYLE_TITLE} or
+	 *            {@link GridUtil#DEFAULT_RASTER_STYLE_TITLE} (if no colorMap is
+	 *            given)
+	 * 
+	 * @return Always a {@link Style} that you can be applyed to a
+	 *         {@link GridCoverage}.
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public static Style createStyleFromColorMap(ColorMap colorMap, String name,
+			String title) {
+		if (colorMap == null)
+			return GridUtil.createDefaultStyle();
+
+		if (name == null)
+			// A colorMap was provided, but no name.
+			name = GridUtil.UNNAMED_RASTER_STYLE_NAME;
+
+		if (title == null)
+			// A colorMap was provided, but no title.
+			title = GridUtil.UNTITLED_RASTER_STYLE_TITLE;
+
+		RasterSymbolizerImpl rasterSymbolizerImpl = new RasterSymbolizerImpl();
+
+		// Entferne alle label informationen
+		clearColorMapLabels(colorMap);
+
+		rasterSymbolizerImpl.setColorMap(colorMap);
+		Symbolizer[] symbolizers = { rasterSymbolizerImpl };
+		RuleImpl ruleImpl = new RuleImpl(symbolizers) {
+		};
+		Rule[] rules = { ruleImpl };
+		FeatureTypeStyleImpl featureTypeStyleImpl = new FeatureTypeStyleImpl(
+				rules) {
+		};
+
+		Style style = STYLE_FACTORY.createStyle();
+		style.setName(name);
+		style.setTitle(title);
+		style.addFeatureTypeStyle(featureTypeStyleImpl);
+		return style;
+	}
+
+	/**
+	 * Removes all label information from the {@link ColorMapEntry}s of the
+	 * given {@link ColorMap}
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public static ColorMap clearColorMapLabels(ColorMap colorMap) {
+		for (ColorMapEntry cme : colorMap.getColorMapEntries()) {
+			cme.setLabel(null);
+		}
+		return colorMap;
+	}
+
+	/**
+	 * Creates a {@link Style} for a {@link Grid} layer from a {@link ColorMap}
+	 * Title will be set to {@link GridUtil#UNTITLED_RASTER_STYLE_TITLE}
+	 * 
+	 * @param colorMap
+	 *            If null, then defaultStyle for Grid will be used
+	 * @param name
+	 *            The name to give to the Style. null will result in name
+	 *            {@link GridUtil#UNTITLED_RASTER_STYLE_TITLE}
+	 * 
+	 * @return Always a Style that you can apply to a {@link GridCoverage}.
+	 *         Style has name {@link GridUtil#DEFAULT_RASTER_STYLE_NAME} if no
+	 *         colormap was provided.
+	 * 
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public static Style createStyleFromColorMap(ColorMap colorMap, String name) {
+		return createStyleFromColorMap(colorMap, name, null);
+	}
+
+	/**
+	 * Loads {@link Style}s from a SLD {@link InputStream}
+	 * 
+	 * @param url
+	 *            {@link URL} to read the SLD from
+	 * 
+	 * @return An {@link Array} of {@link Style}s, can be length==0 if no
+	 *         UserStyles in SLD file. null if file not exists
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public static Style[] loadSLD(URL url) {
+		// LOGGER.debug("Loading styles from URL...");
+		try {
+			return loadSLD(url.openStream());
+		} catch (IOException e) {
+			return null;
+		}
+	}
+
+	/**
+	 * Loads {@link Style}s from a SLD {@link InputStream}
+	 * 
+	 * @param inputStream
+	 *            {@link InputStream} to read the SLD from
+	 * 
+	 * @return An {@link Array} of {@link Style}s, can be length==0. null if
+	 *         file not exists
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public static Style[] loadSLD(InputStream inputStream) {
+		final InputStream inputStream2 = inputStream;
+		if (inputStream2 == null) {
+			return null;
+		}
+
+//		LOGGER.debug("Loading styles from inputStream...");
+
+		SLDParser stylereader;
+		stylereader = new SLDParser(StylingUtil.STYLE_FACTORY);
+		stylereader.setInput(inputStream);
+		Style[] styles = stylereader.readXML();
+
+		if (styles[0] == null) {
+			LOGGER
+					.warn(" ... no Styles recognized in inputStream. Will return empty styles[] array!");
+		} else {
+//			LOGGER.debug(" ... loaded " + styles.length
+//					+ " styles from inputStream, first style's name= "
+//					+ styles[0].getName());
+		}
+
+		// This is the main successful exit form loadSLD
+		return styles;
+	}
+
+	/**
+	 * Loads {@link Style}s from a SLD {@link InputStream} without setting a
+	 * {@link Charset}
+	 * 
+	 * @param inputStream
+	 *            {@link InputStream} to read the SLD from
+	 * 
+	 * @return An {@link Array} of {@link Style}s, can be length==0. null if
+	 *         file not exists
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 * 
+	 * @deprecated
+	 */
+	public static Style[] loadSLDOld(InputStream inputStream) {
+		final InputStream inputStream2 = inputStream;
+		if (inputStream2 == null) {
+			return null;
+		}
+
+		// Reader reader = new UTF8Reader(inputStream2);
+
+		LOGGER.debug("Loading styles from inputStream...");
+
+		SLDParser stylereader;
+		stylereader = new SLDParser(StylingUtil.STYLE_FACTORY, inputStream2);
+		Style[] styles = stylereader.readXML();
+
+		if (styles[0] == null) {
+			LOGGER
+					.warn(" ... no Styles recognized in inputStream. Will return empty styles[] array!");
+		} else {
+			LOGGER.debug(" ... loaded " + styles.length
+					+ " styles from inputStream, first style's name= "
+					+ styles[0].getName());
+		}
+
+		// This is the main successful exit form loadSLD
+		return styles;
+	}
+
+	/**
+	 * Loads {@link Style}s from a SLD {@link File}
+	 * 
+	 * @param sldFile
+	 *            {@link File} to read the SLD from
+	 * 
+	 * @return An {@link Array} of {@link Style}s, can be length==0
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public static Style[] loadSLD(File sldFile) throws FileNotFoundException {
+		LOGGER.debug("Loading styles from File...");
+
+		final Style[] loadedSLD = loadSLD(new FileInputStream(sldFile));
+
+		// TODO Maybe check if names and titles should be set to default
+		// values...
+
+		return loadedSLD;
+	}
+
+	/**
+	 * Saves the {@link Style} to OGC SLD. Overwrites any existing file.
+	 * 
+	 * @param style
+	 *            {@link Style} to save
+	 * @param charset
+	 *            The charset to use for the XML, e.g. <?xml version="1.0"
+	 *            encoding="ISO-8859-1"?>. If null, ISO-8859-1 is used.
+	 * 
+	 * @throws TransformerException
+	 * @throws IOException
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public static final void saveStyleToSLD(Style style, File exportFile,
+			Charset charset) throws TransformerException, IOException {
+		Writer w = null;
+		if (charset != null) {
+			SLDTRANSFORMER.setEncoding(charset);
+		}
+		SLDTRANSFORMER.setIndentation(2);
+		final String xml = SLDTRANSFORMER.transform(style);
+		w = new FileWriter(exportFile);
+		w.write(xml);
+		w.close();
+		LOGGER.info("Saved a Style to " + exportFile + " with charset "
+				+ SLDTRANSFORMER.getEncoding().name());
+	}
+
+	/**
+	 * Saves the {@link Style} to OGC SLD using ISO-8859-1 as charset.
+	 * Overwrites any existing file.
+	 * 
+	 * @param style
+	 *            {@link Style} to save
+	 * 
+	 * @throws TransformerException
+	 * @throws IOException
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public static final void saveStyleToSLD(Style style, File exportFile)
+			throws TransformerException, IOException {
+		saveStyleToSLD(style, exportFile, Charset.forName("ISO-8859-1"));
+	}
+
+	/**
+	 * SLD Rules können die Paramter MinScaleDenominator und MaxScaleDenominator
+	 * enthalten. Dadurch können Elemente für manche Zoom-Stufen deaktiviert
+	 * werden.
+	 * 
+	 * Kommentar: "Sichtbarkeit" bezieht es nicht darauf, ob die Elemente auf
+	 * dem Kartenausschnitt sichtbar sind, sondern um die SLD Regeln, welche das
+	 * Feature evt. nur Scalenabhängig zeichnen.<br/>
+	 * SK 19.6.2009:Bei einem {@link PolygonSymbolizer} zählt nicht der Rand,
+	 * sondern nur ob eine Füllung vorhanden ist! Man kann dann zwar leider
+	 * nicht auf ein Rand eines Polygons ohne Fill klicken, aber dafür kann man
+	 * durch die ungefüllte Fläche klicken.
+	 * 
+	 * @param fc
+	 *            Die zu filternde FeatureCollection. Diese wird nicht
+	 *            verändert.
+	 * @param style
+	 *            Der Style, mit dem die Features gerendert werden (z.b.
+	 *            layer.getStyle() )
+	 * 
+	 * @param scaleDenominator
+	 *            Der aktuelle ScaleDenomitor für den die Sichtbarkeit ermittelt
+	 *            wird.
+	 * 
+	 * @see RendererUtilities.calculateOGCScale
+	 * 
+	 * @return Eine FeatureCollection in welcher nur die Features enthalten
+	 *         sind, welche bei aktuellen Scale mit dem übergebenen Style
+	 *         gerendert werden.
+	 * 
+	 *         TODO Was ist mit raster?!
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public static MemoryFeatureCollection filterSLDVisibleOnly(
+			final FeatureCollection fc, final Style style,
+			final Double scaleDenominator) {
+
+		// Eine im Speicher gehaltene FeatureCollection der sichtbaren
+		final MemoryFeatureCollection fcVisible = new MemoryFeatureCollection(
+				fc.getFeatureType());
+
+		// Prüfen aller Features in der Collection
+		final Iterator<Feature> fcIt = fc.iterator();
+
+		try {
+
+			while (fcIt.hasNext()) {
+				final Feature feature = fcIt.next();
+
+				for (final FeatureTypeStyle fts : style.getFeatureTypeStyles()) {
+					final List<Rule> rules = fts.rules();
+
+					for (final Rule rule : rules) {
+						final double maxScaleDenominator = rule
+								.getMaxScaleDenominator();
+						final double minScaleDenominator = rule
+								.getMinScaleDenominator();
+
+						// 1. Check: Trifft die Rule auf den aktuellen Scale der
+						// JMapPane?
+						if ((minScaleDenominator > scaleDenominator)
+								|| (scaleDenominator > maxScaleDenominator)) {
+							continue;
+						}
+
+						// 2. Check: Eine Rule ist gülrig, aber trifft der
+						// Filter
+						// für dieses Feature?
+						final Filter rFilter = rule.getFilter();
+						if ((rFilter != null) && (!rFilter.evaluate(feature)))
+							continue;
+
+						// 3. Check: Passt einer der Symbolizer dieser Rule zu
+						// dem
+						// Feature? Dieser Check wird in
+						// "real world" meistens klappen, es sei denn, ein
+						// Hansel
+						// gibt einen LineSymbolizer für ein PointLayer an.
+						boolean passt = false;
+						for (final Symbolizer symb : rule.getSymbolizers()) {
+							final Geometry geom = feature.getDefaultGeometry();
+							if ((geom instanceof MultiPoint)
+									|| (geom instanceof com.vividsolutions.jts.geom.Point)) {
+								if (symb instanceof PointSymbolizer) {
+									if (((PointSymbolizer) symb).getGraphic() != null)
+										passt = true;
+									break;
+								}
+							} else if ((geom instanceof MultiLineString)
+									|| (geom instanceof LineString)) {
+								if (symb instanceof LineSymbolizer) {
+									if (((LineSymbolizer) symb).getStroke() != null)
+										passt = true;
+									break;
+								}
+							} else if ((geom instanceof MultiPolygon)
+									|| (geom instanceof Polygon)) {
+								if (symb instanceof PolygonSymbolizer) {
+									if (((PolygonSymbolizer) symb).getFill() != null)
+										passt = true;
+									break;
+								}
+							} else {
+								LOGGER
+										.warn("Unbekannter geom Typ! Gehe von sichbar aus!");
+								passt = true;
+							}
+						}
+						if (!passt)
+							continue;
+
+						// Nun sollte das feature wiklich sichtbar sein
+						fcVisible.add(feature);
+					}
+				}
+			}
+		} catch (final java.lang.IllegalStateException e) {
+			LOGGER.error("Iterating over the features",e);
+			/**
+			 * SK: 14.Apri 2009. It happened a few time to that fcIt.hasNext
+			 * suddenly threw an exception for the "africa countries.shp":
+			 * Exception in thread "AWT-EventQueue-0"
+			 * java.lang.IllegalStateException: ShapeType changed illegally from
+			 * Polygon to Undefined at org.geotools.
+			 * data.shapefile.shp.ShapefileReader.nextRecord(ShapefileReader
+			 * .java:452) at org.geotools.data.shapefile.indexed.
+			 * IndexedShapefileDataStore$Reader
+			 * .next(IndexedShapefileDataStore.java:1272) at
+			 * org.geotools.data.FIDFeatureReader.next(FIDFeatureReader.java:92)
+			 * at org .geotools.data.FilteringFeatureReader.hasNext(
+			 * FilteringFeatureReader .java:125) at
+			 * org.geotools.data.store.FeatureReaderIterator.hasNext(
+			 * FeatureReaderIterator.java:44) at
+			 * schmitzm.geotools.feature.FeatureUtil
+			 * .filterSLDVisibleOnly(FeatureUtil.java:216) *
+			 * 
+			 */
+		}
+
+		// LOGGER.info("filterSLDVisibleOnly removed "+ (fc.size() -
+		// fcVisible.size()) + " features.");
+
+		return fcVisible;
+	}
+
+	/**
+	 * @param style
+	 *            A {@link Style} to search for the first {@link TextSymbolizer}
+	 *            that will be used for the given {@link Feature}.
+	 * 
+	 * @author Stefan A. Krüger
+	 * 
+	 * @return <code>null</code> or the first {@link TextSymbolizer} found in
+	 *         the style that applies to the {@link Feature}.
+	 */
+	public static TextSymbolizer getTextSymbolizer(final Style style,
+			final Feature f) {
+		if (f == null)
+			return null;
+		try {
+			if (style != null) {
+
+				for (final FeatureTypeStyle fts : style.getFeatureTypeStyles()) {
+					for (final Rule r : fts.getRules()) {
+
+						final Filter filter = r.getFilter();
+						//
+						// System.out.println(f);
+						// System.out.println(filter);
+						// System.out.println();
+
+						if (filter != null && (!filter.evaluate(f))) {
+							continue;
+						}
+
+						for (final Symbolizer symb : r.getSymbolizers()) {
+							if (symb instanceof TextSymbolizer) {
+								return (TextSymbolizer) symb;
+							}
+						}
+
+					}
+				}
+
+			}
+
+		} catch (final Exception e) {
+			LOGGER.error("error - filter API stuff?",e);
+			return null;
+		}
+		return null;
+	}
+
+	/**
+	 * @param style
+	 *            A {@link Style} to search for all {@link TextSymbolizer}s . No
+	 *            guarantee, that any one of them will ever be used for any
+	 *            feature (think about filters).
+	 * 
+	 * @author Stefan A. Krüger
+	 * 
+	 * @return {@link List} or all {@link TextSymbolizer}s found in the
+	 *         {@link Style}.
+	 */
+	public static List<TextSymbolizer> getTextSymbolizers(final Style style) {
+		List<TextSymbolizer> results = new ArrayList<TextSymbolizer>();
+		try {
+			if (style != null) {
+
+				for (final FeatureTypeStyle fts : style.getFeatureTypeStyles()) {
+					for (final Rule r : fts.getRules()) {
+						results.addAll(getTextSymbolizers(r.getSymbolizers()));
+					}
+				}
+
+			}
+
+		} catch (final Exception e) {
+			LOGGER.error("error - filter API stuff?",e);
+			return results;
+		}
+		return results;
+	}
+
+	/**
+	 * @param symbolizers
+	 *            List of Symbolizers to search for all {@link TextSymbolizer}s
+	 *            . No guarantee, that any one of them will ever be used for any
+	 *            feature (think about filters).
+	 * 
+	 * @author Stefan A. Krüger
+	 * 
+	 * @return {@link List} or all {@link TextSymbolizer}s found in the given
+	 *         symbolizers.
+	 */
+	public static List<TextSymbolizer> getTextSymbolizers(
+			Symbolizer[] symbolizers) {
+		List<TextSymbolizer> results = new ArrayList<TextSymbolizer>();
+		try {
+			if (symbolizers != null) {
+
+				for (final Symbolizer symb : symbolizers) {
+					if (symb instanceof TextSymbolizer) {
+						results.add((TextSymbolizer) symb);
+					}
+				}
+
+			}
+
+		} catch (final Exception e) {
+			LOGGER.error("error - filter API stuff?",e);
+			return results;
+		}
+		return results;
+	}
+
+	// /**
+	// * Sorts a {@link ColorMap} by its quantity values. This is mentioned in
+	// the
+	// * OGC SLD Definition, page 52:
+	// * <p>
+	// * Quote: For example, a DEM raster giving elevations in meters above sea
+	// * level can be translated to a colored image with a ColorMap. The
+	// quantity
+	// * attributes of a color-map are used for translating between numeric
+	// * matrixes and color rasters and the ColorMap entries should be in order
+	// of
+	// * increasing numeric quantity so that intermediate numeric values can be
+	// * matched to a color (or be interpolated between two colors). Labels may
+	// be
+	// * used for legends or may be used in the future to match character
+	// values.
+	// * Not all systems can support opacity in colormaps. The default opacity
+	// is
+	// * 1.0 (fully opaque). Defaults for quantity and label are
+	// system-dependent.
+	// * </p>
+	// *
+	// * @param colorMap
+	// * {@link ColorMap} to sort by the quantity-field of the
+	// * {@link ColorMapEntry}s
+	// * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	// Kr&uuml;ger</a>
+	// */
+	// public static void sort(RemovableColorMapImpl colorMap) {
+	// ColorMapEntry[] colorMapEntries = colorMap.getColorMapEntries();
+	// SortedMap<Double, ColorMapEntry> tmap = new TreeMap<Double,
+	// ColorMapEntry>();
+	// // Add to a SortedMap
+	// for (ColorMapEntry cme : colorMapEntries) {
+	// tmap.put(getQuantityFromColorMapEntry(cme), cme);
+	// colorMap.removeColorMapEntry(cme);
+	// }
+	// // Recreate ColorMap from sorted quantity values
+	// for (ColorMapEntry cme : tmap.values()) {
+	// colorMap.addColorMapEntry(cme);
+	// }
+	// }
+
+	// /**
+	// * Lets assume that every quantity value is maximally listed once in a
+	// * {@link ColorMap}, then it makes some sense to use it as a key.
+	// *
+	// * @param quantityString
+	// * quantitiy as String
+	// * @return The first colorMap that has the same Quantity ( compared as
+	// * Strings)
+	// *
+	// * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	// Kr&uuml;ger</a>
+	// */
+	// public static ColorMapEntry getColorMapEntryByQuantityString(
+	// ColorMap colorMap, String quantityString) {
+	// for (ColorMapEntry cme : colorMap.getColorMapEntries()) {
+	// if (quantityString.equals(cme.getQuantity().toString()))
+	// return cme;
+	// }
+	// return null;
+	// }
+
+	/**
+	 * Clones a Style by converting it to XML and reading it back in.
+	 * 
+	 * @param style
+	 *            the {@link Style} to be copied.
+	 */
+	public static Style clone(Style style) {
+
+		String xml;
+		try {
+			xml = SLDTRANSFORMER.transform(style);
+
+			SLDParser stylereader;
+			stylereader = new SLDParser(StylingUtil.STYLE_FACTORY,
+					new StringInputStream(xml));
+			Style[] styles = stylereader.readXML();
+
+			return styles[0];
+		} catch (TransformerException e) {
+			ExceptionMonitor.show(null, e);
+			return null;
+		}
+	}
+
+	public static Symbolizer clone(Symbolizer sym) {
+		if (sym == null) {
+			throw new RuntimeException("cant clone null");
+		}
+
+		/**
+		 * Doing some corrections. Otherwise the Symbolizer can not be converted
+		 * to XML
+		 */
+		if (sym instanceof PointSymbolizer) {
+			PointSymbolizer ps = (PointSymbolizer) sym;
+			Graphic graphic = ps.getGraphic();
+
+// That bugfix was needed in 2.4.5 before we patched the StyleFactoryImpl			
+			if (graphic.getSize() instanceof NilExpression) {
+				graphic.setSize(FilterUtil.FILTER_FAC.literal(10.));
+			}
+			
+			
+			try {
+				SLDTRANSFORMER.transform(graphic);
+			} catch (TransformerException e) {
+				LOGGER.error("gr", e);
+			}
+		}
+
+		Style style = STYLE_BUILDER.createStyle(sym); // TODO Mag ich das?
+
+		Filter allwaysTrueFilter = FilterUtil.FILTER_FAC2.equals(
+				FilterUtil.FILTER_FAC2.literal("1"), FilterUtil.FILTER_FAC2
+						.literal("1"));
+
+		style.getFeatureTypeStyles()[0].getRules()[0]
+				.setFilter(allwaysTrueFilter);
+
+		String xml;
+		try {
+			xml = SLDTRANSFORMER.transform(style);
+
+			SLDParser stylereader;
+			stylereader = new SLDParser(StylingUtil.STYLE_FACTORY,
+					new StringInputStream(xml));
+			Style[] styles = stylereader.readXML();
+
+			return (Symbolizer) styles[0].getFeatureTypeStyles()[0].getRules()[0]
+					.getSymbolizers()[0];
+		} catch (TransformerException e) {
+			ExceptionMonitor.show(null, e);
+			return STYLE_FACTORY.createPointSymbolizer(); // TODO Abhängig vom
+			// sym geometry type
+		}
+
+	}
+
+	/**
+	 * Clons a {@link Graphic} element
+	 * 
+	 * @param graphicFill
+	 * @return
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public static Graphic clone(Graphic graphic) {
+		try {
+			PointSymbolizer ps = STYLE_FACTORY.createPointSymbolizer(graphic,
+					"ACHTUNG");
+
+			Style style = STYLE_BUILDER.createStyle(ps);
+
+			final String xml = SLDTRANSFORMER.transform(style);
+
+			SLDParser stylereader;
+			stylereader = new SLDParser(StylingUtil.STYLE_FACTORY,
+					new StringInputStream(xml));
+			Style[] styles = stylereader.readXML();
+
+			PointSymbolizer clonedPs = (PointSymbolizer) styles[0]
+					.getFeatureTypeStyles()[0].getRules()[0].getSymbolizers()[0];
+
+			Graphic clonedG = clonedPs.getGraphic();
+
+			return clonedG;
+
+		} catch (TransformerException e) {
+			LOGGER.error("Cloning a Graphic", e);
+		}
+		return null;
+	}
+
+	/**
+	 * Creates a new {@link BrewerPalette} with only one scheme (which includes
+	 * all colors). The suitablity of the palette is set to "unknown" for all
+	 * viewer types.
+	 * 
+	 * @param name
+	 *            name for the palette (also the description is set to this
+	 *            value)
+	 * @param colors
+	 *            colors for the palette
+	 */
+	public static BrewerPalette createBrewerPalette(String name, Color[] colors)
+			throws IOException {
+		BrewerPalette palette = new BrewerPalette();
+		palette.setColors(colors);
+		palette.setName(name);
+		palette.setDescription(name);
+
+		// set suitability to UNKNOWN for all viewers
+		PaletteSuitability suitability = new PaletteSuitability();
+		suitability.setSuitability(colors.length, new String[] { "?", "?", "?",
+				"?", "?", "?" });
+		palette.setPaletteSuitability(suitability);
+
+		// set the only scheme for the palette (include all colors)
+		int[] schema = new int[colors.length];
+		for (int j = 0; j < schema.length; j++)
+			schema[j] = j;
+		SampleScheme sampleScheme = new SampleScheme();
+		sampleScheme.setSampleScheme(schema.length, schema);
+		palette.setColorScheme(sampleScheme);
+
+		return palette;
+	}
+
+	/**
+	 * @param geoObject
+	 *            {@link GridCoverage2D}, {@link AbstractGridCoverage2DReader},
+	 *            {@link FeatureCollection}, {@link GeometryAttributeType} or
+	 *            {@link FeatureSource}
+	 * 
+	 * @return a {@link Style} that is suitable to identify features of the
+	 *         given type as selected items.
+	 */
+	public static Style createSelectionStyle(Object geoObject) {
+
+		if (geoObject instanceof GridCoverage2D
+				|| geoObject instanceof org.geotools.coverage.grid.io.AbstractGridCoverage2DReader) {
+			// Wenn irgendwann mal selection für raster möglich ist, dann hier
+			// einen schöneren style erstellen.
+			return GridUtil.createDefaultStyle();
+		}
+
+		// We have vector-data. Now let's determine the type...
+		GeometryForm geometryForm = null;
+
+		if (geoObject instanceof FeatureCollection) {
+			geometryForm = FeatureUtil
+					.getGeometryForm((FeatureCollection) geoObject);
+		} else if (geoObject instanceof GeometryAttributeType) {
+			geometryForm = FeatureUtil
+					.getGeometryForm((GeometryAttributeType) geoObject);
+		} else if (geoObject instanceof FeatureSource) {
+			geometryForm = FeatureUtil
+					.getGeometryForm((FeatureSource) geoObject);
+		}
+
+		// /**
+		// * Let's see if we have a cached version of the requested style.
+		// */
+		// if (selectionStyles.containsKey(geometryForm))
+		// return selectionStyles.get(geometryForm);
+
+		Style style = STYLE_FACTORY.createStyle();
+		style.addFeatureTypeStyle(STYLE_FACTORY.createFeatureTypeStyle());
+		Symbolizer[] symbolizers = new Symbolizer[0];
+
+		switch (geometryForm) {
+
+		case POINT:
+			PointSymbolizer ps = STYLE_FACTORY.createPointSymbolizer();
+			ps.setGraphic(SELECTION_GRAPHIC1);
+			symbolizers = LangUtil.extendArray(symbolizers, ps);
+
+			PointSymbolizer ps2 = STYLE_FACTORY.createPointSymbolizer();
+			ps2.setGraphic(SELECTION_GRAPHIC2);
+			symbolizers = LangUtil.extendArray(symbolizers, ps2);
+
+			PointSymbolizer ps3 = STYLE_FACTORY.createPointSymbolizer();
+			ps3.setGraphic(SELECTION_GRAPHIC3);
+			symbolizers = LangUtil.extendArray(symbolizers, ps3);
+
+			break;
+		case POLYGON:
+
+			PolygonSymbolizer polS0 = STYLE_FACTORY.createPolygonSymbolizer();
+
+			Fill SELECTION_FILL0 = STYLE_FACTORY.createFill(STYLE_BUILDER
+					.colorExpression(Color.YELLOW.brighter()));
+
+			polS0.setFill(SELECTION_FILL0);
+			symbolizers = LangUtil.extendArray(symbolizers, polS0);
+
+			PolygonSymbolizer polS = STYLE_FACTORY.createPolygonSymbolizer();
+			polS.setFill(SELECTION_FILL1);
+			symbolizers = LangUtil.extendArray(symbolizers, polS);
+
+		case LINE:
+			LineSymbolizer ls = STYLE_FACTORY.createLineSymbolizer();
+			ls.setStroke(SELECTION_STROKE1);
+			symbolizers = LangUtil.extendArray(symbolizers, ls);
+
+			LineSymbolizer ls2 = STYLE_FACTORY.createLineSymbolizer();
+			ls2.setStroke(SELECTION_STROKE2);
+			symbolizers = LangUtil.extendArray(symbolizers, ls2);
+
+			LineSymbolizer ls3 = STYLE_FACTORY.createLineSymbolizer();
+			ls3.setStroke(SELECTION_STROKE3);
+			symbolizers = LangUtil.extendArray(symbolizers, ls3);
+			break;
+
+		default:
+			throw new IllegalArgumentException("Provide a suitable object.");
+		}
+
+		style.getFeatureTypeStyles()[0].setRules(new Rule[] { STYLE_FACTORY
+				.createRule() });
+		style.getFeatureTypeStyles()[0].getRules()[0]
+				.setSymbolizers(symbolizers);
+
+		// selectionStyles.put(geometryForm, style);
+
+		return style;
+
+	}
+	
+	public static Style createStyleSimple(Object geoObject, Color color, Color color2) {
+		if (geoObject instanceof GridCoverage2D
+				|| geoObject instanceof org.geotools.coverage.grid.io.AbstractGridCoverage2DReader) {
+			// Wenn irgendwann mal selection für raster möglich ist, dann hier
+			// einen schöneren style erstellen.
+			return GridUtil.createDefaultStyle();
+		}
+
+		// We have vector-data. Now let's determine the type...
+		GeometryForm geometryForm = null;
+
+		if (geoObject instanceof FeatureCollection) {
+			geometryForm = FeatureUtil
+					.getGeometryForm((FeatureCollection) geoObject);
+		} else if (geoObject instanceof GeometryAttributeType) {
+			geometryForm = FeatureUtil
+					.getGeometryForm((GeometryAttributeType) geoObject);
+		} else if (geoObject instanceof FeatureSource) {
+			geometryForm = FeatureUtil
+					.getGeometryForm((FeatureSource) geoObject);
+		}
+
+		// /**
+		// * Let's see if we have a cached version of the requested style.
+		// */
+		// if (selectionStyles.containsKey(geometryForm))
+		// return selectionStyles.get(geometryForm);
+
+		Style style = STYLE_FACTORY.createStyle();
+		style.addFeatureTypeStyle(STYLE_FACTORY.createFeatureTypeStyle());
+		Symbolizer[] symbolizers = new Symbolizer[0];
+
+		switch (geometryForm) {
+
+		case POINT:
+			PointSymbolizer ps = STYLE_BUILDER.createPointSymbolizer(STYLE_BUILDER.createGraphic(null, STYLE_BUILDER.createMark("circle"), null));
+			ps.getGraphic().getMarks()[0].setFill(STYLE_BUILDER.createFill(color, 0.5));
+			ps.getGraphic().getMarks()[0].setSize(STYLE_BUILDER.literalExpression(8.));
+			ps.getGraphic().setSize(STYLE_BUILDER.literalExpression(8.));
+			ps.getGraphic().getMarks()[0].setStroke(STYLE_BUILDER.createStroke(color2));
+			symbolizers = LangUtil.extendArray(symbolizers, ps);
+
+			break;
+		case POLYGON:
+			PolygonSymbolizer polS = STYLE_BUILDER.createPolygonSymbolizer(STYLE_BUILDER.createStroke(color2), STYLE_BUILDER.createFill(color));
+			symbolizers = LangUtil.extendArray(symbolizers, polS);
+
+		case LINE:
+			LineSymbolizer ls = STYLE_BUILDER.createLineSymbolizer(STYLE_BUILDER.createStroke(color));
+			symbolizers = LangUtil.extendArray(symbolizers, ls);
+			break;
+
+		default:
+			throw new IllegalArgumentException("Provide a suitable object.");
+		}
+
+		style.getFeatureTypeStyles()[0].setRules(new Rule[] { STYLE_FACTORY
+				.createRule() });
+		style.getFeatureTypeStyles()[0].getRules()[0]
+				.setSymbolizers(symbolizers);
+
+		return style;
+	}
+	
+
+	/**
+	 * Creates a {@link Box} that shows a legend for a list of
+	 * {@link FeatureTypeStyle}s and a targeted featureType
+	 * 
+	 * @param featureType If this a legend for Point, Polygon or Line?
+	 * @param featureTypeStyles The Styles to presen in this legend
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public static Box createLegendPanel(
+			FeatureTypeStyle[] featureTypeStyles, FeatureType featureType) {
+
+		Box box = new Box(BoxLayout.Y_AXIS){
+
+			/**
+			 * Nuetzlich wenn die Componente gedruckt (z.B. wenn ein Screenshot gemacht
+			 * wird) wird. Dann werden wird der Hintergrund auf WEISS gesetzt.
+			 * 
+			 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+			 *         Kr&uuml;ger</a>
+			 */
+			@Override
+			public void print(Graphics g) {
+				final Color orig = getBackground();
+				setBackground(Color.WHITE);
+				// wrap in try/finally so that we always restore the state
+				try {
+					super.print(g);
+				} finally {
+					setBackground(orig);
+				}
+			}
+		};
+
+		for (FeatureTypeStyle ftStyle : featureTypeStyles) {
+
+			// One child-node for every rule
+			Rule[] rules = ftStyle.getRules();
+			for (Rule rule : rules) {
+
+				/**
+				 * Let's not create a hbox for Rules that only contain
+				 * TextSymbolizers
+				 */
+				if (StylingUtil.getTextSymbolizers(rule.getSymbolizers())
+						.size() == rule.getSymbolizers().length)
+					continue;
+
+				Box hbox = new Box( BoxLayout.X_AXIS){
+
+					/**
+					 * Nuetzlich wenn die Componente gedruckt (z.B. wenn ein Screenshot gemacht
+					 * wird) wird. Dann werden wird der Hintergrund auf WEISS gesetzt.
+					 * 
+					 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+					 *         Kr&uuml;ger</a>
+					 */
+					@Override
+					public void print(Graphics g) {
+						final Color orig = getBackground();
+						setBackground(Color.WHITE);
+						// wrap in try/finally so that we always restore the state
+						try {
+							super.print(g);
+						} finally {
+							setBackground(orig);
+						}
+					}
+				};
+
+				/**
+				 * The size of the legend Symbol is dependent on the size of the font.
+				 */
+				final int fontHeight = new JLabel().getFontMetrics(new JLabel().getFont()).getHeight();
+				final Dimension ICON_SIZE = new Dimension(23, fontHeight > 5 ? fontHeight : 5);
+
+
+				// ****************************************************************************
+				// Create the actual icon
+				// ****************************************************************************
+				final BufferedImage imageForRule = LegendIconFeatureRenderer
+						.getInstance().createImageForRule(rule, featureType,
+								ICON_SIZE);
+
+				// LOGGER.debug("Creating a new Legend Image for RUle name =
+				// "+rule.getName());
+
+				ImageIcon legendIcon = new ImageIcon(imageForRule);
+
+				final JLabel iconLabel = new JLabel(legendIcon);
+				hbox.setAlignmentX(0f);
+				hbox.add(iconLabel);
+				hbox.add(Box.createHorizontalStrut(3));
+
+				// ****************************************************************************
+				// The labeltext is read from the SLD. Its either the title
+				// directly, or interpreted as OneLine Code
+				// ****************************************************************************
+				final String rawText = rule.getTitle();
+
+				Translation labelT = new Translation();
+				labelT.fromOneLine(rawText);
+
+				final JLabel classTitleLabel = new JLabel(labelT.toString());
+				hbox.add(classTitleLabel);
+				classTitleLabel.setLabelFor(iconLabel); // Whatever it is good for
+
+				box.add(hbox);
+
+			}
+		}
+
+		return box;
+	}
+
+
+	//
+	// /**
+	// * Doubles the number of palettes by adding the reverse palette to every
+	// * palette. The name of the reverse palette is the name of the original
+	// * palette plus the letter R.
+	// *
+	// * @author SK
+	// * @param palettes The original list of {@link BrewerPalette
+	// BrewerPalettes}
+	// */
+	// public static BrewerPalette[] addReversePalettes(BrewerPalette[]
+	// palettes) {
+	// BrewerPalette[] newPalettes = new BrewerPalette[palettes.length * 2];
+	//
+	// int pos = 0;
+	// for (BrewerPalette bp : palettes) {
+	// newPalettes[pos] = bp;
+	// pos++;
+	// Color[] newColors = new Color[bp.getMaxColors()];
+	//
+	// List<Color> colorList =
+	// java.util.Arrays.asList(bp.getColors(bp.getMaxColors()));
+	// Collections.reverse(colorList);
+	// colorList.toArray(newColors);
+	//
+	// try {
+	// newPalettes[pos] = StylingUtil.createBrewerPalette(bp.getName()
+	// + "R", newColors);
+	// newPalettes[pos].setPaletteSuitability(bp
+	// .getPaletteSuitability());
+	// newPalettes[pos].setDescription(bp.getDescription()+" reversed");
+	// newPalettes[pos].setType(bp.getType());
+	// newPalettes[pos].setColorScheme(bp.getColorScheme());
+	// } catch (IOException e) {
+	// LOGGER.error("",e);
+	// newPalettes[pos] = bp;
+	// }
+	//
+	// pos++;
+	// }
+	//
+	// return newPalettes;
+	// }
+	
+	
+
+	/**
+	 * Replaces the "main" color in a given {@link Symbolizer} element
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public static void replaceSymbolizerColor(Symbolizer symb, Color oldColor,
+			Color newColor) {
+		if (symb == null)
+			return;
+
+		if (symb instanceof PointSymbolizer) {
+			PointSymbolizer ps = (PointSymbolizer) symb;
+			replacePointSymbolizerColor(ps, oldColor, newColor);
+		}
+
+		if (symb instanceof PolygonSymbolizer) {
+			PolygonSymbolizer ps = (PolygonSymbolizer) symb;
+			replacePolygonSymbolizerColor(ps, oldColor, newColor);
+		}
+
+		if (symb instanceof LineSymbolizer) {
+			LineSymbolizer ps = (LineSymbolizer) symb;
+			replaceLineSymbolizerColor(ps, oldColor, newColor);
+		}
+
+	}
+
+	/**
+	 * Replaces the "main" color in a given {@link LineSymbolizer} element
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public static void replaceLineSymbolizerColor(LineSymbolizer ps,
+			Color oldColor, Color newColor) {
+		if (ps == null)
+			return;
+
+		replaceStrokeColor(ps.getStroke(), oldColor, newColor);
+	}
+
+	
+	/**
+	 * Replaces the "main" color in a given {@link PointSymbolizer} element
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public static void replacePointSymbolizerColor(PointSymbolizer ps,
+			Color oldColor, Color newColor) {
+		if (ps == null)
+			return;
+
+		replaceGraphicColor(ps.getGraphic(), oldColor, newColor);
+	}
+
+
+	/**
+	 * Replaces the "main" color in a given {@link PolygonSymbolizer} element
+	 * 
+	 * @param oldColor
+	 * @param newColor
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 * @param ps
+	 */
+	public static void replacePolygonSymbolizerColor(PolygonSymbolizer ps,
+			Color oldColor, Color newColor) {
+		replaceFillColor(ps.getFill(), oldColor, newColor);
+		replaceStrokeColor(ps.getStroke(), oldColor, newColor);
+	}
+
+	/**
+	 * Replaces the "main" color in a given {@link Stroke} element
+	 * @param stroke 
+	 * @param oldColor
+	 * @param newColor
+	 */
+	public static void replaceStrokeColor(Stroke stroke, Color oldColor,
+			Color newColor) {
+		if (stroke == null)
+			return;
+
+		if ((stroke.getColor() != null)
+				&& (StylingUtil.getColorFromExpression(stroke.getColor()).equals(oldColor)))
+			stroke.setColor(StylingUtil.STYLE_BUILDER.colorExpression(newColor));
+
+		replaceGraphicColor(stroke.getGraphicFill(), oldColor, newColor);
+
+		replaceGraphicColor(stroke.getGraphicStroke(), oldColor, newColor);
+
+	}
+
+	/**
+	 * Replaces the "main" color in a given {@link Fill} element
+	 * @param fill
+	 * @param oldColor
+	 * @param newColor
+	 */
+	public static void replaceFillColor(Fill fill, Color oldColor,
+			Color newColor) {
+		if (fill == null)
+			return;
+
+		if ((fill.getColor() != null)
+				&& (getColorFromExpression(fill.getColor()).equals(oldColor)))
+			fill.setColor(STYLE_BUILDER.colorExpression(newColor));
+
+		replaceGraphicColor(fill.getGraphicFill(), oldColor, newColor);
+
+		if ((fill.getBackgroundColor() != null)
+				&& (getColorFromExpression(fill.getBackgroundColor())
+						.equals(oldColor)))
+			fill.setBackgroundColor(STYLE_BUILDER.colorExpression(newColor));
+	}
+
+	/**
+	 * Replaces the "main" color in a given {@link Graphic} element
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public static void replaceGraphicColor(Graphic graphic, Color oldColor,
+			Color newColor) {
+		if (graphic == null)
+			return;
+
+		if ((graphic.getMarks() != null) && (graphic.getMarks().length > 0)) {
+
+			// Checking for Colors in Marks...
+			for (Mark m : graphic.getMarks()) {
+
+				replaceFillColor(m.getFill(), oldColor, newColor);
+
+				replaceStrokeColor(m.getStroke(), oldColor, newColor);
+
+			}
+		}
+	}
+
+
+	/**
+	 * @return the {@link Color} used in the {@link Graphic} or null, if an
+	 *         {@link ExternalGraphic} is used.
+	 * 
+	 * @param graphic
+	 *            If <code>null</code> returns <code>null</code>
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public static Color getGraphicColor(Graphic graphic) {
+		if (graphic == null)
+			return null;
+
+		Color foundColor = null;
+
+		if ((graphic.getMarks() != null) && (graphic.getMarks().length > 0)) {
+
+			// Checking for Colors in Marks...
+			for (Mark m : graphic.getMarks()) {
+
+				if (foundColor == null)
+					foundColor = getFillColor(m.getFill());
+
+				if (foundColor == null)
+					foundColor = getStrokeColor(m.getStroke());
+			}
+
+		}
+
+		return foundColor;
+	}
+
+	/**
+	 * @return the first {@link Color} used in a {@link Stroke}.
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public static Color getStrokeColor(Stroke stroke) {
+		if (stroke == null)
+			return null;
+
+		if (stroke.getColor() != null)
+			return StylingUtil.getColorFromExpression(stroke.getColor());
+
+		if (getGraphicColor(stroke.getGraphicStroke()) != null)
+			return getGraphicColor(stroke.getGraphicStroke());
+
+		if (getGraphicColor(stroke.getGraphicFill()) != null)
+			return getGraphicColor(stroke.getGraphicFill());
+
+		return null;
+	}
+
+	/**
+	 * @return the first {@link Color} used in a {@link Fill}.
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public static Color getFillColor(Fill fill) {
+		if (fill == null)
+			return null;
+
+		Color foundColor = null;
+
+		if (foundColor == null)
+			foundColor = getColorFromExpression(fill.getColor());
+
+		if (foundColor == null)
+			foundColor = getGraphicColor(fill.getGraphicFill());
+
+		if (foundColor == null)
+			foundColor = getColorFromExpression(fill.getBackgroundColor());
+
+		return foundColor;
+	}
+	
+	/**
+	 * @return the first {@link Color} used in a {@link Symbolizer}.
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public static Color getSymbolizerColor(Symbolizer symb) {
+		if (symb == null)
+			return null;
+
+		if (symb instanceof PointSymbolizer) {
+			PointSymbolizer ps = (PointSymbolizer) symb;
+			return getPointSymbolizerColor(ps);
+		}
+
+		if (symb instanceof PolygonSymbolizer) {
+			PolygonSymbolizer ps = (PolygonSymbolizer) symb;
+			return getPolygonSymbolizerColor(ps);
+		}
+
+		if (symb instanceof LineSymbolizer) {
+			LineSymbolizer ps = (LineSymbolizer) symb;
+			return getLineSymbolizerColor(ps);
+		}
+
+		return null;
+	}
+
+	
+	/**
+	 * @return the first {@link Color} used in a {@link LineSymbolizer}.
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public static Color getLineSymbolizerColor(LineSymbolizer ps) {
+		if (ps == null)
+			return null;
+
+		Color foundColor = null;
+
+		if (foundColor == null)
+			foundColor = getStrokeColor(ps.getStroke());
+
+		return foundColor;
+	}
+
+
+	/**
+	 * @return the first {@link Color} used in a {@link PolygonSymbolizer}.
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public static Color getPolygonSymbolizerColor(PolygonSymbolizer ps) {
+		if (ps == null)
+			return null;
+
+		Color foundColor = null;
+
+		if (foundColor == null)
+			foundColor = getFillColor(ps.getFill());
+
+		if (foundColor == null)
+			foundColor = getStrokeColor(ps.getStroke());
+
+		return foundColor;
+	}
+
+
+	/**
+	 * @return the first {@link Color} used in a {@link PointSymbolizer}.
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public static Color getPointSymbolizerColor(PointSymbolizer ps) {
+		if (ps == null)
+			return null;
+
+		return getGraphicColor(ps.getGraphic());
+	}
+
+
+	/***************************************************************************
+	 * Copies all Values from one {@link TextSymbolizer} to another
+	 * {@link TextSymbolizer}
+	 * 
+	 * @param from {@link TextSymbolizer} source
+	 * @param to {@link TextSymbolizer} target. May not be <code>null</code>.
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public static void copyAllValues(final TextSymbolizer from,
+			final TextSymbolizer to) {
+		to.setLabel(from.getLabel());
+		
+		final FilterFactory2 ff2 = FeatureUtil.FILTER_FACTORY2;
+		
+		to.getFonts()[0].setFontFamily(ff2.literal(from.getFonts()[0]
+				.getFontFamily().toString()));
+		to.getFonts()[0].setFontSize(ff2.literal(from.getFonts()[0]
+				.getFontSize().toString()));
+		to.getFonts()[0].setFontWeight(ff2.literal(from.getFonts()[0]
+				.getFontWeight().toString()));
+		to.getFonts()[0].setFontStyle(ff2.literal(from.getFonts()[0]
+				.getFontStyle().toString()));
+	}
+
+
+}

Modified: trunk/src/schmitzm/io/BinaryInputBuffer.java
===================================================================
--- trunk/src/schmitzm/io/BinaryInputBuffer.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/io/BinaryInputBuffer.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,185 +1,203 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.io;
-
-/**
- * <hr>
- * <small><i>Diese Klasse wurde urspruenglich 2002/2003 von <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- *            fuer die ADAGIOS-Java-Library (Universitaet Bonn) erstellt, 2009 in das
- *            SCHMITZM-Projekt uebernommen und teilweise erweitert.</i></small>
- * <hr>
- * Der <code>BinaryInputBuffer</code> erweitert den <code>InputBuffer</code>
- * durch die Moeglichkeit, neben einzelnen Bytes, auch die Binaerdarstellung
- * ganze Zahlen (mehrere Bytes auf einen Schub) in den Buffer schreiben
- * zu koennen.<br>
- * Um in gleicherweise ganze Zahlen aus dem Buffer zu lesen, kann die
- * Klasse <code>adagios.types.BinaryInputStream</code> verwendet werden:<br>
- * <code>
- * BinaryInputBuffer buf = new BinaryInputBuffer(1000);<br>
- * BinaryInputStream inp = new BinaryInputStream( buf );<br>
- * buf.writeInt( 123456 );<br>
- * buf.writeShort( 1000 );<br>
- * int i = inp.readInt();<br>
- * int s = inp.readShort();<br>
- * </code><br>
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class BinaryInputBuffer extends InputBuffer {
-
-  /**
-   * Erzeugt einen neuen <code>BinaryInputBuffer</code> der Groesse 1024.
-   */
-  public BinaryInputBuffer() {
-    this(1024);
-  }
-
-  /**
-   * Erzeugt einen neuen <code>BinaryInputBuffer</code>.
-   * @param byteSize Groesse des Buffers in Byte
-   */
-  public BinaryInputBuffer(int byteSize) {
-    super(byteSize);
-  }
-
-  /**
-   * Schreibt einen <code>char</code>-Wert (2 Byte) in den Buffer.
-   * Hierbei wird das 2er-Komplement verwendet.
-   * @param byteOrder BigEndian/LittleEndian (vgl. {@link BinaryUtil})
-   * @param c         zu schreibender Char
-   * @see schmitzm.io.BinaryUtil#XDR
-   * @see schmitzm.io.BinaryUtil#NDR
-   * @see schmitzm.io.BinaryUtil#convertLongToBytes(byte,long,int)
-   */
-  public void writeChar(byte byteOrder, char c) {
-    write( BinaryUtil.convertLongToBytes(byteOrder,c,2) );
-  }
-
-  /**
-   * Schreibt einen <code>char</code>-Wert (2 Byte) in den Buffer.
-   * Hierbei wird das 2er-Komplement in <i>BigEndian</i> verwendet.
-   * @param c zu schreibender Char
-   * @see schmitzm.io.BinaryUtil#XDR
-   * @see #writeChar(byte,char)
-   */
-  public void writeChar(char c) {
-    writeChar( BinaryUtil.XDR, c );
-  }
-
-  /**
-   * Schreibt einen <code>short</code>-Wert (2 Byte) in den Buffer.
-   * Hierbei wird das 2er-Komplement verwendet.
-   * @param byteOrder BigEndian/LittleEndian (vgl. {@link BinaryUtil})
-   * @param s         zu schreibender Short
-   * @see schmitzm.io.BinaryUtil#XDR
-   * @see schmitzm.io.BinaryUtil#NDR
-   * @see schmitzm.io.BinaryUtil#convertLongToBytes(byte,long,int)
-   */
-  public void writeShort(byte byteOrder, short s) {
-    write( BinaryUtil.convertLongToBytes(byteOrder,s,2) );
-  }
-
-  /**
-   * Schreibt einen <code>short</code>-Wert (2 Byte) in den Buffer.
-   * Hierbei wird das 2er-Komplement in <i>BigEndian</i> verwendet.
-   * @param s zu schreibender Short
-   * @see schmitzm.io.BinaryUtil#XDR
-   * @see #writeShort(byte,short)
-   */
-  public void writeShort(short s) {
-    writeShort( BinaryUtil.XDR, s );
-  }
-
-  /**
-   * Schreibt einen <code>int</code>-Wert (4 Byte) in den Buffer.
-   * Hierbei wird das 2er-Komplement verwendet.
-   * @param byteOrder BigEndian/LittleEndian (vgl. {@link BinaryUtil})
-   * @param i         zu schreibender Int
-   * @see schmitzm.io.BinaryUtil#XDR
-   * @see schmitzm.io.BinaryUtil#NDR
-   * @see schmitzm.io.BinaryUtil#convertLongToBytes(byte,long,int)
-   */
-  public void writeInt(byte byteOrder, int i) {
-    write( BinaryUtil.convertLongToBytes(byteOrder,i,4) );
-  }
-
-  /**
-   * Schreibt einen <code>int</code>-Wert (4 Byte) in den Buffer.
-   * Hierbei wird das 2er-Komplement in <i>BigEndian</i> verwendet.
-   * @param i zu schreibender Int
-   * @see schmitzm.io.BinaryUtil#XDR
-   * @see #writeInt(byte,int)
-   */
-  public void writeInt(int i) {
-    writeInt( BinaryUtil.XDR, i );
-  }
-
-  /**
-   * Schreibt einen <code>long</code>-Wert (8 Byte) in den Buffer.
-   * Hierbei wird das 2er-Komplement verwendet.
-   * @param byteOrder BigEndian/LittleEndian (vgl. {@link BinaryUtil})
-   * @param l         zu schreibender Long
-   * @see schmitzm.io.BinaryUtil#XDR
-   * @see schmitzm.io.BinaryUtil#NDR
-   * @see schmitzm.io.BinaryUtil#convertLongToBytes(byte,long,int)
-   */
-  public void writeLong(byte byteOrder, long l) {
-    write( BinaryUtil.convertLongToBytes(byteOrder,l,8) );
-  }
-
-  /**
-   * Schreibt einen <code>long</code>-Wert (8 Byte) in den Buffer.
-   * Hierbei wird das 2er-Komplement in <i>BigEndian</i> verwendet.
-   * @param l zu schreibender Long
-   * @see schmitzm.io.BinaryUtil#XDR
-   * @see #writeLong(byte,long)
-   */
-  public void writeLong(long l) {
-    writeLong( BinaryUtil.XDR, l );
-  }
-
-  /**
-   * Schreibt einen <code>float</code>-Wert (4 Byte) in den Buffer.
-   * @param byteOrder BigEndian/LittleEndian (vgl. {@link BinaryUtil})
-   * @param f         zu schreibender Float
-   * @see schmitzm.io.BinaryUtil#XDR
-   * @see schmitzm.io.BinaryUtil#NDR
-   * @see schmitzm.io.BinaryUtil#convertFloatToBytes(byte,float)
-   */
-  public void writeFloat(byte byteOrder, float f) {
-    write( BinaryUtil.convertFloatToBytes(byteOrder,f) );
-  }
-
-  /**
-   * Schreibt einen <code>double</code>-Wert (8 Byte) in den Buffer.
-   * @param byteOrder BigEndian/LittleEndian (vgl. {@link BinaryUtil})
-   * @param d         zu schreibender Double
-   * @see schmitzm.io.BinaryUtil#XDR
-   * @see schmitzm.io.BinaryUtil#NDR
-   * @see schmitzm.io.BinaryUtil#convertDoubleToBytes(byte,double)
-   */
-  public void writeDouble(byte byteOrder, double d) {
-    write( BinaryUtil.convertDoubleToBytes(byteOrder,d) );
-  }
-
-  /**
-   * Schreibt einen <code>float</code>-Wert (8 Byte) in den Buffer.
-   * Hierbei wird <i>BigEndian</i> verwendet.
-   * @param f zu schreibender Float
-   * @see schmitzm.io.BinaryUtil#XDR
-   * @see #writeFloat(byte,float)
-   */
-  public void writeFloat(float f) {
-    writeFloat( BinaryUtil.XDR, f );
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.io;
+
+/**
+ * <hr>
+ * <small><i>Diese Klasse wurde urspruenglich 2002/2003 von <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *            fuer die ADAGIOS-Java-Library (Universitaet Bonn) erstellt, 2009 in das
+ *            SCHMITZM-Projekt uebernommen und teilweise erweitert.</i></small>
+ * <hr>
+ * Der <code>BinaryInputBuffer</code> erweitert den <code>InputBuffer</code>
+ * durch die Moeglichkeit, neben einzelnen Bytes, auch die Binaerdarstellung
+ * ganze Zahlen (mehrere Bytes auf einen Schub) in den Buffer schreiben
+ * zu koennen.<br>
+ * Um in gleicherweise ganze Zahlen aus dem Buffer zu lesen, kann die
+ * Klasse <code>adagios.types.BinaryInputStream</code> verwendet werden:<br>
+ * <code>
+ * BinaryInputBuffer buf = new BinaryInputBuffer(1000);<br>
+ * BinaryInputStream inp = new BinaryInputStream( buf );<br>
+ * buf.writeInt( 123456 );<br>
+ * buf.writeShort( 1000 );<br>
+ * int i = inp.readInt();<br>
+ * int s = inp.readShort();<br>
+ * </code><br>
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class BinaryInputBuffer extends InputBuffer {
+
+  /**
+   * Erzeugt einen neuen <code>BinaryInputBuffer</code> der Groesse 1024.
+   */
+  public BinaryInputBuffer() {
+    this(1024);
+  }
+
+  /**
+   * Erzeugt einen neuen <code>BinaryInputBuffer</code>.
+   * @param byteSize Groesse des Buffers in Byte
+   */
+  public BinaryInputBuffer(int byteSize) {
+    super(byteSize);
+  }
+
+  /**
+   * Schreibt einen <code>char</code>-Wert (2 Byte) in den Buffer.
+   * Hierbei wird das 2er-Komplement verwendet.
+   * @param byteOrder BigEndian/LittleEndian (vgl. {@link BinaryUtil})
+   * @param c         zu schreibender Char
+   * @see schmitzm.io.BinaryUtil#XDR
+   * @see schmitzm.io.BinaryUtil#NDR
+   * @see schmitzm.io.BinaryUtil#convertLongToBytes(byte,long,int)
+   */
+  public void writeChar(byte byteOrder, char c) {
+    write( BinaryUtil.convertLongToBytes(byteOrder,c,2) );
+  }
+
+  /**
+   * Schreibt einen <code>char</code>-Wert (2 Byte) in den Buffer.
+   * Hierbei wird das 2er-Komplement in <i>BigEndian</i> verwendet.
+   * @param c zu schreibender Char
+   * @see schmitzm.io.BinaryUtil#XDR
+   * @see #writeChar(byte,char)
+   */
+  public void writeChar(char c) {
+    writeChar( BinaryUtil.XDR, c );
+  }
+
+  /**
+   * Schreibt einen <code>short</code>-Wert (2 Byte) in den Buffer.
+   * Hierbei wird das 2er-Komplement verwendet.
+   * @param byteOrder BigEndian/LittleEndian (vgl. {@link BinaryUtil})
+   * @param s         zu schreibender Short
+   * @see schmitzm.io.BinaryUtil#XDR
+   * @see schmitzm.io.BinaryUtil#NDR
+   * @see schmitzm.io.BinaryUtil#convertLongToBytes(byte,long,int)
+   */
+  public void writeShort(byte byteOrder, short s) {
+    write( BinaryUtil.convertLongToBytes(byteOrder,s,2) );
+  }
+
+  /**
+   * Schreibt einen <code>short</code>-Wert (2 Byte) in den Buffer.
+   * Hierbei wird das 2er-Komplement in <i>BigEndian</i> verwendet.
+   * @param s zu schreibender Short
+   * @see schmitzm.io.BinaryUtil#XDR
+   * @see #writeShort(byte,short)
+   */
+  public void writeShort(short s) {
+    writeShort( BinaryUtil.XDR, s );
+  }
+
+  /**
+   * Schreibt einen <code>int</code>-Wert (4 Byte) in den Buffer.
+   * Hierbei wird das 2er-Komplement verwendet.
+   * @param byteOrder BigEndian/LittleEndian (vgl. {@link BinaryUtil})
+   * @param i         zu schreibender Int
+   * @see schmitzm.io.BinaryUtil#XDR
+   * @see schmitzm.io.BinaryUtil#NDR
+   * @see schmitzm.io.BinaryUtil#convertLongToBytes(byte,long,int)
+   */
+  public void writeInt(byte byteOrder, int i) {
+    write( BinaryUtil.convertLongToBytes(byteOrder,i,4) );
+  }
+
+  /**
+   * Schreibt einen <code>int</code>-Wert (4 Byte) in den Buffer.
+   * Hierbei wird das 2er-Komplement in <i>BigEndian</i> verwendet.
+   * @param i zu schreibender Int
+   * @see schmitzm.io.BinaryUtil#XDR
+   * @see #writeInt(byte,int)
+   */
+  public void writeInt(int i) {
+    writeInt( BinaryUtil.XDR, i );
+  }
+
+  /**
+   * Schreibt einen <code>long</code>-Wert (8 Byte) in den Buffer.
+   * Hierbei wird das 2er-Komplement verwendet.
+   * @param byteOrder BigEndian/LittleEndian (vgl. {@link BinaryUtil})
+   * @param l         zu schreibender Long
+   * @see schmitzm.io.BinaryUtil#XDR
+   * @see schmitzm.io.BinaryUtil#NDR
+   * @see schmitzm.io.BinaryUtil#convertLongToBytes(byte,long,int)
+   */
+  public void writeLong(byte byteOrder, long l) {
+    write( BinaryUtil.convertLongToBytes(byteOrder,l,8) );
+  }
+
+  /**
+   * Schreibt einen <code>long</code>-Wert (8 Byte) in den Buffer.
+   * Hierbei wird das 2er-Komplement in <i>BigEndian</i> verwendet.
+   * @param l zu schreibender Long
+   * @see schmitzm.io.BinaryUtil#XDR
+   * @see #writeLong(byte,long)
+   */
+  public void writeLong(long l) {
+    writeLong( BinaryUtil.XDR, l );
+  }
+
+  /**
+   * Schreibt einen <code>float</code>-Wert (4 Byte) in den Buffer.
+   * @param byteOrder BigEndian/LittleEndian (vgl. {@link BinaryUtil})
+   * @param f         zu schreibender Float
+   * @see schmitzm.io.BinaryUtil#XDR
+   * @see schmitzm.io.BinaryUtil#NDR
+   * @see schmitzm.io.BinaryUtil#convertFloatToBytes(byte,float)
+   */
+  public void writeFloat(byte byteOrder, float f) {
+    write( BinaryUtil.convertFloatToBytes(byteOrder,f) );
+  }
+
+  /**
+   * Schreibt einen <code>double</code>-Wert (8 Byte) in den Buffer.
+   * @param byteOrder BigEndian/LittleEndian (vgl. {@link BinaryUtil})
+   * @param d         zu schreibender Double
+   * @see schmitzm.io.BinaryUtil#XDR
+   * @see schmitzm.io.BinaryUtil#NDR
+   * @see schmitzm.io.BinaryUtil#convertDoubleToBytes(byte,double)
+   */
+  public void writeDouble(byte byteOrder, double d) {
+    write( BinaryUtil.convertDoubleToBytes(byteOrder,d) );
+  }
+
+  /**
+   * Schreibt einen <code>float</code>-Wert (8 Byte) in den Buffer.
+   * Hierbei wird <i>BigEndian</i> verwendet.
+   * @param f zu schreibender Float
+   * @see schmitzm.io.BinaryUtil#XDR
+   * @see #writeFloat(byte,float)
+   */
+  public void writeFloat(float f) {
+    writeFloat( BinaryUtil.XDR, f );
+  }
+
+}

Modified: trunk/src/schmitzm/io/BinaryInputStream.java
===================================================================
--- trunk/src/schmitzm/io/BinaryInputStream.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/io/BinaryInputStream.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,157 +1,175 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.io;
-
-import java.io.ByteArrayInputStream;
-import java.io.DataInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * <hr>
- * <small><i>Diese Klasse wurde urspruenglich 2002/2003 von <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- *            fuer die ADAGIOS-Java-Library (Universitaet Bonn) erstellt, 2009 in das
- *            SCHMITZM-Projekt uebernommen und teilweise erweitert.</i></small>
- * <hr>
- * <code>BinaryInputStream</code> erweitert die Klasse
- * <code>java.io.DataInputStream</code> um Methoden, mit denen man Werte
- * wahlweise in <i>BigEndian</i> oder <i>LittleEndian</i> aus dem Stream
- * auslesen kann.<br>
- * Die geerbten Methoden von <code>DataInputStream</code> interpretieren
- * die Byte-Folgen immer als <i>BigEndian</i> (das erste Byte im Stream
- * ist das hoechstwertige Byte für den zu lesenenden Wert).
- * @see java.io.DataInputStream
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class BinaryInputStream extends DataInputStream {
-  /**
-   * Erzeugt einen neuen Binary-Eingabestream.
-   */
-  public BinaryInputStream(InputStream in) {
-    super(in);
-  }
-
-  /**
-   * Erzeugt einen neuen Binary-Eingabestream, in dem aus dem
-   * <code>byte</code>-Array ein {@link ByteArrayInputStream}
-   * erzeugt wird.
-   * @see java.io.ByteArrayInputStream
-   */
-  public BinaryInputStream(byte[] bytes) {
-    this( new ByteArrayInputStream(bytes) );
-  }
-
-  /**
-   * Erzeugt einen neuen Binary-Eingabestream, in dem aus dem String
-   * ein {@link ByteArrayInputStream} erzeugt wird.
-   * @see java.io.ByteArrayInputStream
-   */
-  public BinaryInputStream(String str) {
-    this( new ByteArrayInputStream(str.getBytes()) );
-  }
-
-  /**
-   * Liefert einen {@link InputStream} als {@link BinaryInputStream}.
-   * Ist der uebergebene <code>InputStream</code> bereits eine Instanz von
-   * <code>BinaryInputStream</code> wird diese (gecastet) zurueckgegeben.
-   * Ansonsten wird eine neue <code>BinaryInputStream</code>-Instanz aus dem
-   * <code>InputStream</code> erzeugt.
-   */
-  public static BinaryInputStream fromInputStream(InputStream in) {
-    if (in instanceof BinaryInputStream) return (BinaryInputStream)in;
-    return new BinaryInputStream(in);
-  }
-
-  /**
-   * Liest einen <code>char</code>-Wert (2 Bytes) aus dem Stream.
-   * Dabei wird das 2er-Komplement verwendet.
-   * @param byteOrder BigEndian/LittleEndian (vgl. {@link BinaryUtil})
-   * @see BinaryUtil#XDR
-   * @see BinaryUtil#NDR
-   * @see BinaryUtil#convertBytesToLong(byte,InputStream,int)
-   */
-  public char readChar(byte byteOrder) throws IOException {
-    return (char)BinaryUtil.convertBytesToLong(byteOrder,this,2);
-  }
-
-  /**
-   * Liest einen <code>short</code>-Wert (2 Bytes) aus dem Stream.
-   * Dabei wird das 2er-Komplement verwendet.
-   * @param byteOrder BigEndian/LittleEndian (vgl. {@link BinaryUtil})
-   * @see BinaryUtil#XDR
-   * @see BinaryUtil#NDR
-   * @see BinaryUtil#convertBytesToLong(byte,InputStream,int)
-   */
-  public short readShort(byte byteOrder) throws IOException {
-    return (short)BinaryUtil.convertBytesToLong(byteOrder,this,2);
-  }
-
-  /**
-   * Liest einen <code>short</code>-Wert (2 Bytes) aus dem Stream, der ohne
-   * Vorzeichen interpretiert wird. Dabei wird das 2er-Komplement verwendet.
-   * @param byteOrder BigEndian/LittleEndian (vgl. {@link BinaryUtil})
-   * @see BinaryUtil#XDR
-   * @see BinaryUtil#NDR
-   * @see BinaryUtil#convertBytesToLong(byte,InputStream,int)
-   */
-  public int readUnsignedShort(byte byteOrder) throws IOException {
-    return (int)BinaryUtil.convertBytesToLong(byteOrder,this,2);
-  }
-
-  /**
-   * Liest einen <code>int</code>-Wert (4 Bytes) aus dem Stream.
-   * Dabei wird das 2er-Komplement verwendet.
-   * @param byteOrder BigEndian/LittleEndian (vgl. {@link BinaryUtil})
-   * @see BinaryUtil#XDR
-   * @see BinaryUtil#NDR
-   * @see BinaryUtil#convertBytesToLong(byte,InputStream,int)
-   */
-  public int readInt(byte byteOrder) throws IOException {
-    return (int)BinaryUtil.convertBytesToLong(byteOrder,this,4);
-  }
-
-  /**
-   * Liest einen <code>long</code>-Wert (8 Bytes) aus dem Stream.
-   * Dabei wird das 2er-Komplement verwendet.
-   * @param byteOrder BigEndian/LittleEndian (vgl. {@link BinaryUtil})
-   * @see BinaryUtil#XDR
-   * @see BinaryUtil#NDR
-   * @see BinaryUtil#convertBytesToLong(byte,InputStream,int)
-   */
-  public long readLong(byte byteOrder) throws IOException {
-    return (long)BinaryUtil.convertBytesToLong(byteOrder,this,8);
-  }
-
-  /**
-   * Liest einen <code>double</code>-Wert (8 Bytes) aus dem Stream.
-   * @param byteOrder BigEndian/LittleEndian (vgl. {@link BinaryUtil})
-   * @see BinaryUtil#XDR
-   * @see BinaryUtil#NDR
-   * @see BinaryUtil#convertBytesToDouble(byte,InputStream)
-   */
-  public double readDouble(byte byteOrder) throws IOException {
-    return (double)BinaryUtil.convertBytesToDouble(byteOrder,this);
-  }
-
-  /**
-   * Liest einen <code>float</code>-Wert (4 Bytes) aus dem Stream.
-   * @param byteOrder BigEndian/LittleEndian (vgl. {@link BinaryUtil})
-   * @see BinaryUtil#XDR
-   * @see BinaryUtil#NDR
-   * @see BinaryUtil#convertBytesToFloat(byte,InputStream)
-   */
-  public float readFloat(byte byteOrder) throws IOException {
-    return (long)BinaryUtil.convertBytesToFloat(byteOrder,this);
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.io;
+
+import java.io.ByteArrayInputStream;
+import java.io.DataInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * <hr>
+ * <small><i>Diese Klasse wurde urspruenglich 2002/2003 von <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *            fuer die ADAGIOS-Java-Library (Universitaet Bonn) erstellt, 2009 in das
+ *            SCHMITZM-Projekt uebernommen und teilweise erweitert.</i></small>
+ * <hr>
+ * <code>BinaryInputStream</code> erweitert die Klasse
+ * <code>java.io.DataInputStream</code> um Methoden, mit denen man Werte
+ * wahlweise in <i>BigEndian</i> oder <i>LittleEndian</i> aus dem Stream
+ * auslesen kann.<br>
+ * Die geerbten Methoden von <code>DataInputStream</code> interpretieren
+ * die Byte-Folgen immer als <i>BigEndian</i> (das erste Byte im Stream
+ * ist das hoechstwertige Byte für den zu lesenenden Wert).
+ * @see java.io.DataInputStream
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class BinaryInputStream extends DataInputStream {
+  /**
+   * Erzeugt einen neuen Binary-Eingabestream.
+   */
+  public BinaryInputStream(InputStream in) {
+    super(in);
+  }
+
+  /**
+   * Erzeugt einen neuen Binary-Eingabestream, in dem aus dem
+   * <code>byte</code>-Array ein {@link ByteArrayInputStream}
+   * erzeugt wird.
+   * @see java.io.ByteArrayInputStream
+   */
+  public BinaryInputStream(byte[] bytes) {
+    this( new ByteArrayInputStream(bytes) );
+  }
+
+  /**
+   * Erzeugt einen neuen Binary-Eingabestream, in dem aus dem String
+   * ein {@link ByteArrayInputStream} erzeugt wird.
+   * @see java.io.ByteArrayInputStream
+   */
+  public BinaryInputStream(String str) {
+    this( new ByteArrayInputStream(str.getBytes()) );
+  }
+
+  /**
+   * Liefert einen {@link InputStream} als {@link BinaryInputStream}.
+   * Ist der uebergebene <code>InputStream</code> bereits eine Instanz von
+   * <code>BinaryInputStream</code> wird diese (gecastet) zurueckgegeben.
+   * Ansonsten wird eine neue <code>BinaryInputStream</code>-Instanz aus dem
+   * <code>InputStream</code> erzeugt.
+   */
+  public static BinaryInputStream fromInputStream(InputStream in) {
+    if (in instanceof BinaryInputStream) return (BinaryInputStream)in;
+    return new BinaryInputStream(in);
+  }
+
+  /**
+   * Liest einen <code>char</code>-Wert (2 Bytes) aus dem Stream.
+   * Dabei wird das 2er-Komplement verwendet.
+   * @param byteOrder BigEndian/LittleEndian (vgl. {@link BinaryUtil})
+   * @see BinaryUtil#XDR
+   * @see BinaryUtil#NDR
+   * @see BinaryUtil#convertBytesToLong(byte,InputStream,int)
+   */
+  public char readChar(byte byteOrder) throws IOException {
+    return (char)BinaryUtil.convertBytesToLong(byteOrder,this,2);
+  }
+
+  /**
+   * Liest einen <code>short</code>-Wert (2 Bytes) aus dem Stream.
+   * Dabei wird das 2er-Komplement verwendet.
+   * @param byteOrder BigEndian/LittleEndian (vgl. {@link BinaryUtil})
+   * @see BinaryUtil#XDR
+   * @see BinaryUtil#NDR
+   * @see BinaryUtil#convertBytesToLong(byte,InputStream,int)
+   */
+  public short readShort(byte byteOrder) throws IOException {
+    return (short)BinaryUtil.convertBytesToLong(byteOrder,this,2);
+  }
+
+  /**
+   * Liest einen <code>short</code>-Wert (2 Bytes) aus dem Stream, der ohne
+   * Vorzeichen interpretiert wird. Dabei wird das 2er-Komplement verwendet.
+   * @param byteOrder BigEndian/LittleEndian (vgl. {@link BinaryUtil})
+   * @see BinaryUtil#XDR
+   * @see BinaryUtil#NDR
+   * @see BinaryUtil#convertBytesToLong(byte,InputStream,int)
+   */
+  public int readUnsignedShort(byte byteOrder) throws IOException {
+    return (int)BinaryUtil.convertBytesToLong(byteOrder,this,2);
+  }
+
+  /**
+   * Liest einen <code>int</code>-Wert (4 Bytes) aus dem Stream.
+   * Dabei wird das 2er-Komplement verwendet.
+   * @param byteOrder BigEndian/LittleEndian (vgl. {@link BinaryUtil})
+   * @see BinaryUtil#XDR
+   * @see BinaryUtil#NDR
+   * @see BinaryUtil#convertBytesToLong(byte,InputStream,int)
+   */
+  public int readInt(byte byteOrder) throws IOException {
+    return (int)BinaryUtil.convertBytesToLong(byteOrder,this,4);
+  }
+
+  /**
+   * Liest einen <code>long</code>-Wert (8 Bytes) aus dem Stream.
+   * Dabei wird das 2er-Komplement verwendet.
+   * @param byteOrder BigEndian/LittleEndian (vgl. {@link BinaryUtil})
+   * @see BinaryUtil#XDR
+   * @see BinaryUtil#NDR
+   * @see BinaryUtil#convertBytesToLong(byte,InputStream,int)
+   */
+  public long readLong(byte byteOrder) throws IOException {
+    return (long)BinaryUtil.convertBytesToLong(byteOrder,this,8);
+  }
+
+  /**
+   * Liest einen <code>double</code>-Wert (8 Bytes) aus dem Stream.
+   * @param byteOrder BigEndian/LittleEndian (vgl. {@link BinaryUtil})
+   * @see BinaryUtil#XDR
+   * @see BinaryUtil#NDR
+   * @see BinaryUtil#convertBytesToDouble(byte,InputStream)
+   */
+  public double readDouble(byte byteOrder) throws IOException {
+    return (double)BinaryUtil.convertBytesToDouble(byteOrder,this);
+  }
+
+  /**
+   * Liest einen <code>float</code>-Wert (4 Bytes) aus dem Stream.
+   * @param byteOrder BigEndian/LittleEndian (vgl. {@link BinaryUtil})
+   * @see BinaryUtil#XDR
+   * @see BinaryUtil#NDR
+   * @see BinaryUtil#convertBytesToFloat(byte,InputStream)
+   */
+  public float readFloat(byte byteOrder) throws IOException {
+    return (long)BinaryUtil.convertBytesToFloat(byteOrder,this);
+  }
+
+}

Modified: trunk/src/schmitzm/io/BinaryUtil.java
===================================================================
--- trunk/src/schmitzm/io/BinaryUtil.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/io/BinaryUtil.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,334 +1,352 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.io;
-
-import java.io.EOFException;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * <hr>
- * <small><i>Diese Klasse wurde urspruenglich 2002/2003 von <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- *            fuer die ADAGIOS-Java-Library (Universitaet Bonn) erstellt, 2009 in das
- *            SCHMITZM-Projekt uebernommen und teilweise erweitert.</i></small>
- * <hr>
- * Diese Klasse enthaelt statische Methoden, die das Arbeiten mit Binaerstrings
- * erleichtern.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class BinaryUtil {
-
-  /**
-   * Numerische Konstante fuer die ByteOrder 'Big Endian'.<br>
-   * Dabei steht das hoechstwertige Byte im ERSTEN Byte einer Folge.
-   */
-  public static final byte XDR = 0;
-
-  /**
-   * Numerische Konstante fuer die ByteOrder 'Little Endian'.<br>
-   * Dabei steht das niederstwertige Byte im ERSTEN Byte einer Folge.
-   */
-  public static final byte NDR = 1;
-
-
-  /**
-   * Konvertiert Bytes eines Streams in einen <code>long</code>-Wert.
-   * @param byteOrder 0 = BigEndian = hoechstwertiges Byte zuerst,
-   *                  1 = LittleEndian = niederwertigstes Byte zuerst
-   * @param input     Eingabe-Stream
-   * @param byteCount Anzahl der Bytes, die aus dem Stream gelesen und in einen
-   *                  Long umgewandelt werden sollen
-   * @exception java.io.IOException falls das Lesen aus dem Stream scheitert
-   * @exception java.io.EOFException falls nicht genug Bytes auf dem Stream liegen
-   */
-  public static long convertBytesToLong(byte byteOrder, InputStream input, int byteCount) throws IOException {
-    byte[] bytes = new byte[byteCount];
-    if ( input.read(bytes) < byteCount )
-      throw new EOFException("Not enough Bytes available on InputStream");
-
-    return convertBytesToLong(byteOrder,bytes);
-  }
-
-  /**
-   * Konvertiert eine Reihe von Bytes in einen <code>long</code>-Wert.<br>
-   * Fuer negative Werte wird eine Darstellung im 2er-Komplement erwartet.
-   * @param byteOrder 0 = BigEndian = hoechstwertiges Byte zuerst,
-   *                  1 = LittleEndian = niederwertigstes Byte zuerst
-   * @param bytes     Eingabe-Bytes
-   */
-  public static long convertBytesToLong(byte byteOrder, byte[] bytes) {
-    if (bytes == null || bytes.length == 0)
-      throw new ArrayIndexOutOfBoundsException("At least 1 Byte needed for convert to long!!");
-
-    // Bemerkung:
-    // ==========
-    // Wegen des sukzessiven Bit-Shift, muss die Summierung mit dem
-    // hoechstwertigen Byte begonnen werden.
-    // Dies steht bei 'BigEndian' im ersten, bei 'LittleEndian' im
-    // letzten Byte.
-    // Der zusaetzliche Summand 256 (wenn bytes[i]<0), ist notwendig, da
-    // der Wertebereich von 'byte' von -128 bis +127 reicht (nicht 0..255!!).
-    // Ein einfacher Cast von 'byte' zu 'char' ist leider nicht ausreichend,
-    // da 'char' durch 16Bit repraesentiert wird. Beim Cast wird das
-    // Vorzeichen-Bit also einfach uebernommen und der Wert bleibt unveraendert.
-    // Was gaebe ich in diesem Moment fuer das kleine Woertchen 'unsigned'!! :-)
-
-    // Das erste Bit des hoechstwerigen Bytes ist das Vorzeichenbit. Um das
-    // Vorzeichen im long-Ergebnis zu erhalten, muessen die fuehrenden Bits
-    // (die durch den byte-Array nicht abgedeckt werden) mit diesem VZ-Bit
-    // belegt werden.
-    // Dies geht am Einfachsten in dem man das Ergebnis initial komplett mit
-    // dem VZ-Bit belegt:
-    // a) hoechstwertiges Byte in long konvertierten
-    //    --> nun hat 'result' dasselbe VZ wie die in bytes[] kodierte Zahl
-    // b) die Bits des hoechstwertigen Bytes eliminieren, die nicht das VZ-Bit
-    //    sind (durch den Rechts-Shift wird linkt mit dem VZ-Bit aufgefuellt!)
-    long result = (byteOrder == XDR) ? bytes[0] : bytes[bytes.length-1];
-    result >>= 7;
-
-    if ( byteOrder == XDR )
-      // Big Endian (hoechstwertiges Byte zuerst im Array)
-      for(int i=0; i<bytes.length; i++)
-//      result = (result << 8) + bytes[i] + (bytes[i]<0 ? 256 : 0);
-        result = (result << 8) | getUnsignedByte(bytes[i]);
-    else
-      // Little Endian (niederwertiges Byte zuerst im Array)
-      for(int i=bytes.length-1; i >= 0; i--) {
-//      result = (result << 8) + bytes[i] + (bytes[i]<0 ? 256 : 0);
-        result = (result << 8) | getUnsignedByte(bytes[i]);
-      }
-    return result;
-  }
-
-  /**
-   * Konvertiert 4 Bytes eines Streams in einen <code>float</code>-Wert.
-   * @param byteOrder 0 = BigEndian = hoechstwertiges Byte zuerst,
-   *                  1 = LittleEndian = niederwertigstes Byte zuerst
-   * @param input     Eingabe-Stream
-   * @exception java.io.IOException falls das Lesen aus dem Stream scheitert
-   * @exception java.io.EOFException falls nicht genug Bytes auf dem Stream liegen
-   */
-  public static float convertBytesToFloat(byte byteOrder, InputStream input) throws IOException {
-    byte[] bytes = new byte[4];
-    if ( input.read(bytes) < 4 )
-      throw new EOFException("Not enough Bytes available on InputStream");
-
-    return convertBytesToFloat(byteOrder,bytes);
-  }
-
-  /**
-   * Konvertiert 4 Bytes in einen <code>float</code>-Wert.<br>
-   * @param byteOrder 0 = BigEndian = hoechstwertiges Byte zuerst,
-   *                  1 = LittleEndian = niederwertigstes Byte zuerst
-   * @param bytes     8 Eingabe-Bytes
-   */
-  public static float convertBytesToFloat(byte byteOrder, byte[] bytes) {
-    if (bytes == null || bytes.length != 4)
-      throw new ArrayIndexOutOfBoundsException("Exactly 4 Byte needed for convert to float!!");
-
-    // Bytes wie einen Integer einlesen
-    int intValue = (int)convertBytesToLong(byteOrder, bytes);
-    // Bits in Float konvertieren
-    return Float.intBitsToFloat( intValue );
-  }
-
-  /**
-   * Konvertiert 8 Bytes eines Streams in einen <code>double</code>-Wert.
-   * @param byteOrder 0 = BigEndian = hoechstwertiges Byte zuerst,
-   *                  1 = LittleEndian = niederwertigstes Byte zuerst
-   * @param input     Eingabe-Stream
-   * @exception java.io.IOException falls das Lesen aus dem Stream scheitert
-   * @exception java.io.EOFException falls nicht genug Bytes auf dem Stream liegen
-   */
-  public static double convertBytesToDouble(byte byteOrder, InputStream input) throws IOException {
-    byte[] bytes = new byte[8];
-    if ( input.read(bytes) < 8 )
-      throw new EOFException("Not enough Bytes available on InputStream");
-
-    return convertBytesToDouble(byteOrder,bytes);
-  }
-
-  /**
-   * Konvertiert 8 Bytes in einen <code>double</code>-Wert.<br>
-   * @param byteOrder 0 = BigEndian = hoechstwertiges Byte zuerst,
-   *                  1 = LittleEndian = niederwertigstes Byte zuerst
-   * @param bytes     8 Eingabe-Bytes
-   */
-  public static double convertBytesToDouble(byte byteOrder, byte[] bytes) {
-    if (bytes == null || bytes.length != 8)
-      throw new ArrayIndexOutOfBoundsException("Exactly 8 Byte needed for convert to double!!");
-
-    // Bytes wie einen Long einlesen
-    long longValue = convertBytesToLong(byteOrder, bytes);
-    // Bits in Double konvertieren
-    return Double.longBitsToDouble( longValue );
-  }
-
-  /**
-   * Konvertiert einen <code>long</code>-Wert in eine Reihe von Bytes.
-   * Fuer negative Werte wird das 2er-Komplement verwendet.
-   * @param byteOrder 0 = BigEndian = hoechstwertiges Byte zuerst,
-   *                  1 = LittleEndian = niederwertigstes Byte zuerst
-   * @param value     Eingabewert
-   * @param size      Groesse des Rueckgabe-Arrays; unbenoetigte Felder werden
-   *                  aufgefuellt (fuer negative Werte mit 1, sonst mit 0);<br>
-   *                  Bei <code>size=0</code> ist der Rueckgabe-Array genau
-   *                  so gross wie noetig.
-   * @exception java.lang.ArrayIndexOutOfBoundException falls der long-Wert
-   *            nicht in den Rueckgabe-Array passt.
-   */
-  public static byte[] convertLongToBytes(byte byteOrder, long value, int size) {
-    // 2er-Komplement fuer negative Zahlen:
-    // a) Verwende den positiven Wert
-    // b) Subtrahiere 1
-    // c) Bestimme die Bytes nach B+V (Betrag+VZ)
-    // d) invertiere alle Bits
-    if ( value < 0) {
-      long posValue = Math.abs(value) - 1;                        // a) & b)
-      byte[] bytes = convertLongToBytes(byteOrder,posValue,size); // c)
-      for (int i=0; i<bytes.length; i++) bytes[i] ^= -1;          // d)
-      return bytes;
-    }
-
-    // Anzahl an Bytes, die fuer die Zahl benoetigt werden (im 2er-Komplement)
-    // --> multiplikation mit 2 (Bitshift!), da ein Bit mehr fuer das
-    //     Vorzeichen benoetigt wird
-    int bytesNeeded = (int)(Math.log(value<<1)/Math.log(256) + 1);
-    if ( bytesNeeded > size )
-      throw new ArrayIndexOutOfBoundsException(bytesNeeded+" Bytes needed to store "+value+" in 2's complement!!");
-
-    // Wert in B+V ausrechenen
-    byte[] bytes = new byte[ size==0 ? bytesNeeded : size ];
-    int i=0; // Array-Zaehler
-    // erstmal in LittleEndian ausrechnen
-    for(int potenz=0; value>0; i++, potenz++) {
-//    bytes[i] = (byte)(value%256);
-//    value /= 256;
-      bytes[i] = (byte)(value & 255);
-      value >>= 8; // naechstes Byte
-    }
-
-    // Big Endian (hoechstwertiges Byte zuerst)
-    // --> Array-Reihenfolge vertauschen
-    if ( byteOrder == XDR ) {
-      for (i=0; i<bytes.length/2; i++){
-        // Dreieckstausch
-        byte help = bytes[i];
-        bytes[i] = bytes[bytes.length-i-1];
-        bytes[bytes.length-i-1] = help;
-      }
-    }
-
-    return bytes;
-  }
-
-  /**
-   * Konvertiert einen <code>long</code>-Wert in eine Reihe von Bytes.
-   * Fuer negative Werte wird das 2er-Komplement verwendet.
-   * Die Bytes werden allerdings nicht als <code>byte</code> zurueckgegeben,
-   * sondern als <code>int</code>, der einen <code>unsigned byte</code>
-   * simuliert.<br>
-   * Es werden also immer positive Werte zurueckgegeben!!
-   * @param byteOrder 0 = BigEndian = hoechstwertiges Byte zuerst,
-   *                  1 = LittleEndian = niederwertigstes Byte zuerst
-   * @param value     Eingabewert
-   * @param size      Groesse des Rueckgabe-Arrays; unbenoetigte Felder werden
-   *                  aufgefuellt (fuer negative Werte mit 1, sonst mit 0);<br>
-   *                  Bei <code>size=0</code> ist der Rueckgabe-Array genau
-   *                  so gross wie noetig.
-   * @exception java.lang.ArrayIndexOutOfBoundException falls der long-Wert
-   *            nicht in den Rueckgabe-Array passt.
-   */
-  public static int[] convertLongToUnsignedBytes(byte byteOrder, long value, int size) {
-    return getUnsignedBytes( convertLongToBytes(byteOrder,value,size) );
-  }
-
-  /**
-   * Konvertiert einen <code>byte</code>-Wert (-128..127) in ein
-   * <i>unsigned</i> <code>byte</code> (0..255).
-   * Der Rueckgabetyp muss hierfuer ein <code>int</code> sein.
-   * @param b Wert zwischen -128 und 127
-   * @return <code>(int)b & 255</code>
-   */
-  public static int getUnsignedByte(byte b) {
-    return (int)b & 255;
-  }
-
-  /**
-   * Konvertiert einen Array von <code>byte</code>-Werten (-128..127) in einen
-   * Array von <i>unsigned</i> <code>bytes</code> (0..255).
-   * Der Rueckgabetyp muss hierfuer ein <code>int</code> sein.
-   * @param signedByte {@code byte}-Array
-   */
-  public static int[] getUnsignedBytes(byte signedByte[]) {
-    int[] unsignedByte = new int[ signedByte.length ];
-    for (int i=0; i<signedByte.length; i++)
-      unsignedByte[i] = getUnsignedByte( signedByte[i] );
-    return unsignedByte;
-  }
-
-  /**
-   * Konvertiert einen <code>float</code>-Wert in 4 Bytes.
-   * @param byteOrder 0 = BigEndian = hoechstwertiges Byte zuerst,
-   *                  1 = LittleEndian = niederwertigstes Byte zuerst
-   * @param value     Eingabewert
-   * @return byte[4]
-   */
-  public static byte[] convertFloatToBytes(byte byteOrder, float value) {
-    int intValue = Float.floatToIntBits(value);
-    return convertLongToBytes(byteOrder, intValue, 4);
-  }
-
-  /**
-   * Konvertiert einen <code>float</code>-Wert in 4 Bytes.
-   * Die Bytes werden allerdings nicht als <code>byte</code> zurueckgegeben,
-   * sondern als <code>int</code>, der einen <code>unsigned byte</code>
-   * simuliert.<br>
-   * Es werden also immer positive Werte zurueckgegeben!!
-   * @param byteOrder 0 = BigEndian = hoechstwertiges Byte zuerst,
-   *                  1 = LittleEndian = niederwertigstes Byte zuerst
-   * @param value     Eingabewert
-   * @return byte[4]
-   */
-  public static int[] convertFloatToUnsignedBytes(byte byteOrder, float value) {
-    return getUnsignedBytes( convertFloatToBytes(byteOrder,value) );
-  }
-
-  /**
-   * Konvertiert einen <code>double</code>-Wert in 8 Bytes.
-   * @param byteOrder 0 = BigEndian = hoechstwertiges Byte zuerst,
-   *                  1 = LittleEndian = niederwertigstes Byte zuerst
-   * @param value     Eingabewert
-   * @return byte[8]
-   */
-  public static byte[] convertDoubleToBytes(byte byteOrder, double value) {
-    long longValue = Double.doubleToLongBits(value);
-    return convertLongToBytes(byteOrder, longValue, 8);
-  }
-
-  /**
-   * Konvertiert einen <code>double</code>-Wert in 8 Bytes.
-   * Die Bytes werden allerdings nicht als <code>byte</code> zurueckgegeben,
-   * sondern als <code>int</code>, der einen <code>unsigned byte</code>
-   * simuliert.<br>
-   * Es werden also immer positive Werte zurueckgegeben!!
-   * @param byteOrder 0 = BigEndian = hoechstwertiges Byte zuerst,
-   *                  1 = LittleEndian = niederwertigstes Byte zuerst
-   * @param value     Eingabewert
-   * @return byte[8]
-   */
-  public static int[] convertDoubleToUnsignedBytes(byte byteOrder, double value) {
-    return getUnsignedBytes( convertDoubleToBytes(byteOrder,value) );
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.io;
+
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * <hr>
+ * <small><i>Diese Klasse wurde urspruenglich 2002/2003 von <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *            fuer die ADAGIOS-Java-Library (Universitaet Bonn) erstellt, 2009 in das
+ *            SCHMITZM-Projekt uebernommen und teilweise erweitert.</i></small>
+ * <hr>
+ * Diese Klasse enthaelt statische Methoden, die das Arbeiten mit Binaerstrings
+ * erleichtern.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class BinaryUtil {
+
+  /**
+   * Numerische Konstante fuer die ByteOrder 'Big Endian'.<br>
+   * Dabei steht das hoechstwertige Byte im ERSTEN Byte einer Folge.
+   */
+  public static final byte XDR = 0;
+
+  /**
+   * Numerische Konstante fuer die ByteOrder 'Little Endian'.<br>
+   * Dabei steht das niederstwertige Byte im ERSTEN Byte einer Folge.
+   */
+  public static final byte NDR = 1;
+
+
+  /**
+   * Konvertiert Bytes eines Streams in einen <code>long</code>-Wert.
+   * @param byteOrder 0 = BigEndian = hoechstwertiges Byte zuerst,
+   *                  1 = LittleEndian = niederwertigstes Byte zuerst
+   * @param input     Eingabe-Stream
+   * @param byteCount Anzahl der Bytes, die aus dem Stream gelesen und in einen
+   *                  Long umgewandelt werden sollen
+   * @exception java.io.IOException falls das Lesen aus dem Stream scheitert
+   * @exception java.io.EOFException falls nicht genug Bytes auf dem Stream liegen
+   */
+  public static long convertBytesToLong(byte byteOrder, InputStream input, int byteCount) throws IOException {
+    byte[] bytes = new byte[byteCount];
+    if ( input.read(bytes) < byteCount )
+      throw new EOFException("Not enough Bytes available on InputStream");
+
+    return convertBytesToLong(byteOrder,bytes);
+  }
+
+  /**
+   * Konvertiert eine Reihe von Bytes in einen <code>long</code>-Wert.<br>
+   * Fuer negative Werte wird eine Darstellung im 2er-Komplement erwartet.
+   * @param byteOrder 0 = BigEndian = hoechstwertiges Byte zuerst,
+   *                  1 = LittleEndian = niederwertigstes Byte zuerst
+   * @param bytes     Eingabe-Bytes
+   */
+  public static long convertBytesToLong(byte byteOrder, byte[] bytes) {
+    if (bytes == null || bytes.length == 0)
+      throw new ArrayIndexOutOfBoundsException("At least 1 Byte needed for convert to long!!");
+
+    // Bemerkung:
+    // ==========
+    // Wegen des sukzessiven Bit-Shift, muss die Summierung mit dem
+    // hoechstwertigen Byte begonnen werden.
+    // Dies steht bei 'BigEndian' im ersten, bei 'LittleEndian' im
+    // letzten Byte.
+    // Der zusaetzliche Summand 256 (wenn bytes[i]<0), ist notwendig, da
+    // der Wertebereich von 'byte' von -128 bis +127 reicht (nicht 0..255!!).
+    // Ein einfacher Cast von 'byte' zu 'char' ist leider nicht ausreichend,
+    // da 'char' durch 16Bit repraesentiert wird. Beim Cast wird das
+    // Vorzeichen-Bit also einfach uebernommen und der Wert bleibt unveraendert.
+    // Was gaebe ich in diesem Moment fuer das kleine Woertchen 'unsigned'!! :-)
+
+    // Das erste Bit des hoechstwerigen Bytes ist das Vorzeichenbit. Um das
+    // Vorzeichen im long-Ergebnis zu erhalten, muessen die fuehrenden Bits
+    // (die durch den byte-Array nicht abgedeckt werden) mit diesem VZ-Bit
+    // belegt werden.
+    // Dies geht am Einfachsten in dem man das Ergebnis initial komplett mit
+    // dem VZ-Bit belegt:
+    // a) hoechstwertiges Byte in long konvertierten
+    //    --> nun hat 'result' dasselbe VZ wie die in bytes[] kodierte Zahl
+    // b) die Bits des hoechstwertigen Bytes eliminieren, die nicht das VZ-Bit
+    //    sind (durch den Rechts-Shift wird linkt mit dem VZ-Bit aufgefuellt!)
+    long result = (byteOrder == XDR) ? bytes[0] : bytes[bytes.length-1];
+    result >>= 7;
+
+    if ( byteOrder == XDR )
+      // Big Endian (hoechstwertiges Byte zuerst im Array)
+      for(int i=0; i<bytes.length; i++)
+//      result = (result << 8) + bytes[i] + (bytes[i]<0 ? 256 : 0);
+        result = (result << 8) | getUnsignedByte(bytes[i]);
+    else
+      // Little Endian (niederwertiges Byte zuerst im Array)
+      for(int i=bytes.length-1; i >= 0; i--) {
+//      result = (result << 8) + bytes[i] + (bytes[i]<0 ? 256 : 0);
+        result = (result << 8) | getUnsignedByte(bytes[i]);
+      }
+    return result;
+  }
+
+  /**
+   * Konvertiert 4 Bytes eines Streams in einen <code>float</code>-Wert.
+   * @param byteOrder 0 = BigEndian = hoechstwertiges Byte zuerst,
+   *                  1 = LittleEndian = niederwertigstes Byte zuerst
+   * @param input     Eingabe-Stream
+   * @exception java.io.IOException falls das Lesen aus dem Stream scheitert
+   * @exception java.io.EOFException falls nicht genug Bytes auf dem Stream liegen
+   */
+  public static float convertBytesToFloat(byte byteOrder, InputStream input) throws IOException {
+    byte[] bytes = new byte[4];
+    if ( input.read(bytes) < 4 )
+      throw new EOFException("Not enough Bytes available on InputStream");
+
+    return convertBytesToFloat(byteOrder,bytes);
+  }
+
+  /**
+   * Konvertiert 4 Bytes in einen <code>float</code>-Wert.<br>
+   * @param byteOrder 0 = BigEndian = hoechstwertiges Byte zuerst,
+   *                  1 = LittleEndian = niederwertigstes Byte zuerst
+   * @param bytes     8 Eingabe-Bytes
+   */
+  public static float convertBytesToFloat(byte byteOrder, byte[] bytes) {
+    if (bytes == null || bytes.length != 4)
+      throw new ArrayIndexOutOfBoundsException("Exactly 4 Byte needed for convert to float!!");
+
+    // Bytes wie einen Integer einlesen
+    int intValue = (int)convertBytesToLong(byteOrder, bytes);
+    // Bits in Float konvertieren
+    return Float.intBitsToFloat( intValue );
+  }
+
+  /**
+   * Konvertiert 8 Bytes eines Streams in einen <code>double</code>-Wert.
+   * @param byteOrder 0 = BigEndian = hoechstwertiges Byte zuerst,
+   *                  1 = LittleEndian = niederwertigstes Byte zuerst
+   * @param input     Eingabe-Stream
+   * @exception java.io.IOException falls das Lesen aus dem Stream scheitert
+   * @exception java.io.EOFException falls nicht genug Bytes auf dem Stream liegen
+   */
+  public static double convertBytesToDouble(byte byteOrder, InputStream input) throws IOException {
+    byte[] bytes = new byte[8];
+    if ( input.read(bytes) < 8 )
+      throw new EOFException("Not enough Bytes available on InputStream");
+
+    return convertBytesToDouble(byteOrder,bytes);
+  }
+
+  /**
+   * Konvertiert 8 Bytes in einen <code>double</code>-Wert.<br>
+   * @param byteOrder 0 = BigEndian = hoechstwertiges Byte zuerst,
+   *                  1 = LittleEndian = niederwertigstes Byte zuerst
+   * @param bytes     8 Eingabe-Bytes
+   */
+  public static double convertBytesToDouble(byte byteOrder, byte[] bytes) {
+    if (bytes == null || bytes.length != 8)
+      throw new ArrayIndexOutOfBoundsException("Exactly 8 Byte needed for convert to double!!");
+
+    // Bytes wie einen Long einlesen
+    long longValue = convertBytesToLong(byteOrder, bytes);
+    // Bits in Double konvertieren
+    return Double.longBitsToDouble( longValue );
+  }
+
+  /**
+   * Konvertiert einen <code>long</code>-Wert in eine Reihe von Bytes.
+   * Fuer negative Werte wird das 2er-Komplement verwendet.
+   * @param byteOrder 0 = BigEndian = hoechstwertiges Byte zuerst,
+   *                  1 = LittleEndian = niederwertigstes Byte zuerst
+   * @param value     Eingabewert
+   * @param size      Groesse des Rueckgabe-Arrays; unbenoetigte Felder werden
+   *                  aufgefuellt (fuer negative Werte mit 1, sonst mit 0);<br>
+   *                  Bei <code>size=0</code> ist der Rueckgabe-Array genau
+   *                  so gross wie noetig.
+   * @exception java.lang.ArrayIndexOutOfBoundException falls der long-Wert
+   *            nicht in den Rueckgabe-Array passt.
+   */
+  public static byte[] convertLongToBytes(byte byteOrder, long value, int size) {
+    // 2er-Komplement fuer negative Zahlen:
+    // a) Verwende den positiven Wert
+    // b) Subtrahiere 1
+    // c) Bestimme die Bytes nach B+V (Betrag+VZ)
+    // d) invertiere alle Bits
+    if ( value < 0) {
+      long posValue = Math.abs(value) - 1;                        // a) & b)
+      byte[] bytes = convertLongToBytes(byteOrder,posValue,size); // c)
+      for (int i=0; i<bytes.length; i++) bytes[i] ^= -1;          // d)
+      return bytes;
+    }
+
+    // Anzahl an Bytes, die fuer die Zahl benoetigt werden (im 2er-Komplement)
+    // --> multiplikation mit 2 (Bitshift!), da ein Bit mehr fuer das
+    //     Vorzeichen benoetigt wird
+    int bytesNeeded = (int)(Math.log(value<<1)/Math.log(256) + 1);
+    if ( bytesNeeded > size )
+      throw new ArrayIndexOutOfBoundsException(bytesNeeded+" Bytes needed to store "+value+" in 2's complement!!");
+
+    // Wert in B+V ausrechenen
+    byte[] bytes = new byte[ size==0 ? bytesNeeded : size ];
+    int i=0; // Array-Zaehler
+    // erstmal in LittleEndian ausrechnen
+    for(int potenz=0; value>0; i++, potenz++) {
+//    bytes[i] = (byte)(value%256);
+//    value /= 256;
+      bytes[i] = (byte)(value & 255);
+      value >>= 8; // naechstes Byte
+    }
+
+    // Big Endian (hoechstwertiges Byte zuerst)
+    // --> Array-Reihenfolge vertauschen
+    if ( byteOrder == XDR ) {
+      for (i=0; i<bytes.length/2; i++){
+        // Dreieckstausch
+        byte help = bytes[i];
+        bytes[i] = bytes[bytes.length-i-1];
+        bytes[bytes.length-i-1] = help;
+      }
+    }
+
+    return bytes;
+  }
+
+  /**
+   * Konvertiert einen <code>long</code>-Wert in eine Reihe von Bytes.
+   * Fuer negative Werte wird das 2er-Komplement verwendet.
+   * Die Bytes werden allerdings nicht als <code>byte</code> zurueckgegeben,
+   * sondern als <code>int</code>, der einen <code>unsigned byte</code>
+   * simuliert.<br>
+   * Es werden also immer positive Werte zurueckgegeben!!
+   * @param byteOrder 0 = BigEndian = hoechstwertiges Byte zuerst,
+   *                  1 = LittleEndian = niederwertigstes Byte zuerst
+   * @param value     Eingabewert
+   * @param size      Groesse des Rueckgabe-Arrays; unbenoetigte Felder werden
+   *                  aufgefuellt (fuer negative Werte mit 1, sonst mit 0);<br>
+   *                  Bei <code>size=0</code> ist der Rueckgabe-Array genau
+   *                  so gross wie noetig.
+   * @exception java.lang.ArrayIndexOutOfBoundException falls der long-Wert
+   *            nicht in den Rueckgabe-Array passt.
+   */
+  public static int[] convertLongToUnsignedBytes(byte byteOrder, long value, int size) {
+    return getUnsignedBytes( convertLongToBytes(byteOrder,value,size) );
+  }
+
+  /**
+   * Konvertiert einen <code>byte</code>-Wert (-128..127) in ein
+   * <i>unsigned</i> <code>byte</code> (0..255).
+   * Der Rueckgabetyp muss hierfuer ein <code>int</code> sein.
+   * @param b Wert zwischen -128 und 127
+   * @return <code>(int)b & 255</code>
+   */
+  public static int getUnsignedByte(byte b) {
+    return (int)b & 255;
+  }
+
+  /**
+   * Konvertiert einen Array von <code>byte</code>-Werten (-128..127) in einen
+   * Array von <i>unsigned</i> <code>bytes</code> (0..255).
+   * Der Rueckgabetyp muss hierfuer ein <code>int</code> sein.
+   * @param signedByte {@code byte}-Array
+   */
+  public static int[] getUnsignedBytes(byte signedByte[]) {
+    int[] unsignedByte = new int[ signedByte.length ];
+    for (int i=0; i<signedByte.length; i++)
+      unsignedByte[i] = getUnsignedByte( signedByte[i] );
+    return unsignedByte;
+  }
+
+  /**
+   * Konvertiert einen <code>float</code>-Wert in 4 Bytes.
+   * @param byteOrder 0 = BigEndian = hoechstwertiges Byte zuerst,
+   *                  1 = LittleEndian = niederwertigstes Byte zuerst
+   * @param value     Eingabewert
+   * @return byte[4]
+   */
+  public static byte[] convertFloatToBytes(byte byteOrder, float value) {
+    int intValue = Float.floatToIntBits(value);
+    return convertLongToBytes(byteOrder, intValue, 4);
+  }
+
+  /**
+   * Konvertiert einen <code>float</code>-Wert in 4 Bytes.
+   * Die Bytes werden allerdings nicht als <code>byte</code> zurueckgegeben,
+   * sondern als <code>int</code>, der einen <code>unsigned byte</code>
+   * simuliert.<br>
+   * Es werden also immer positive Werte zurueckgegeben!!
+   * @param byteOrder 0 = BigEndian = hoechstwertiges Byte zuerst,
+   *                  1 = LittleEndian = niederwertigstes Byte zuerst
+   * @param value     Eingabewert
+   * @return byte[4]
+   */
+  public static int[] convertFloatToUnsignedBytes(byte byteOrder, float value) {
+    return getUnsignedBytes( convertFloatToBytes(byteOrder,value) );
+  }
+
+  /**
+   * Konvertiert einen <code>double</code>-Wert in 8 Bytes.
+   * @param byteOrder 0 = BigEndian = hoechstwertiges Byte zuerst,
+   *                  1 = LittleEndian = niederwertigstes Byte zuerst
+   * @param value     Eingabewert
+   * @return byte[8]
+   */
+  public static byte[] convertDoubleToBytes(byte byteOrder, double value) {
+    long longValue = Double.doubleToLongBits(value);
+    return convertLongToBytes(byteOrder, longValue, 8);
+  }
+
+  /**
+   * Konvertiert einen <code>double</code>-Wert in 8 Bytes.
+   * Die Bytes werden allerdings nicht als <code>byte</code> zurueckgegeben,
+   * sondern als <code>int</code>, der einen <code>unsigned byte</code>
+   * simuliert.<br>
+   * Es werden also immer positive Werte zurueckgegeben!!
+   * @param byteOrder 0 = BigEndian = hoechstwertiges Byte zuerst,
+   *                  1 = LittleEndian = niederwertigstes Byte zuerst
+   * @param value     Eingabewert
+   * @return byte[8]
+   */
+  public static int[] convertDoubleToUnsignedBytes(byte byteOrder, double value) {
+    return getUnsignedBytes( convertDoubleToBytes(byteOrder,value) );
+  }
+
+}

Modified: trunk/src/schmitzm/io/CombinedInputStream.java
===================================================================
--- trunk/src/schmitzm/io/CombinedInputStream.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/io/CombinedInputStream.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,148 +1,166 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.io;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * <hr>
- * <small><i>Diese Klasse wurde urspruenglich 2002/2003 von <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- *            fuer die ADAGIOS-Java-Library (Universitaet Bonn) erstellt, 2009 in das
- *            SCHMITZM-Projekt uebernommen und teilweise erweitert.</i></small>
- * <hr>
- * Diese Klasse stellt einen Eingabe-Stream dar, der Daten auf Basis
- * mehrerer anderen <code>InputStream</code>-Instanzen liefert. Zunaechst
- * werden Bytes aus dem ersten Stream geliefert, wenn dieser Stream keine
- * Daten mehr liefern kann aus dem zweiten, usw.<br>
- * Sobald ein Stream einmal komplett geleert wurde, liefert die
- * <code>read()</code>-Methode nur noch Bytes aus einem der naechsten
- * Streams. Auch wenn der "leere" Stream spaeter wieder Daten liefern koennte,
- * werden diese nicht mehr beruecksichtigt, sondern einfach ignoriert.<br>
- * Diese Klasse kann z.B. verwendet werden, um bereits aus einem InputStream
- * gelesene Daten (z.B. einen Header) diesem wieder voranzustellen, um
- * den InputStream "als Original" weiterzugeben.<br>
- * <b><u>Beispiel</u>:</b><br>
- * Ein Klasse liest Text-Repraesentationenen <u>unterschiedlicher</u> Typen
- * aus einer Datei. Erst nachdem der Header eines jeden Objekts eingelesen
- * wurde, kann entschieden werden, welche Typ-Klasse instanziiert werden muss.
- * Um deren <code>initFromText(InputStream)</code>-Methode aufrufen zu koennen,
- * wird aber wieder der komplette InputStream inklusive Header benoetigt.<br>
- * Hierzu kann ein <code>CombinedInputStream</code>, zusammengesetzt aus einem
- * neuen <code>ByteArrayInputStream</code> fuer den bereits eingelesenen
- * Header und dem Eingabe-Stream der Datei, erzeugt werden, welcher der
- * <code>initFromText(InputStream)</code>-Methode uebergeben wird.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class CombinedInputStream extends InputStream {
-  private InputStream[] input     = null;
-  private int           actStream = 0;
-  private int           avBytes   = 0;
-
-
-  /**
-   * Erzeugt einen neuen <code>CombinedInputStream</code>.
-   * @param input Eingabe-Streams aus denen sukzessive gelesen wird
-   * @exception java.io.IOException falls beim Ermitteln der insgesamt
-   *            zur Verfuegung stehenden Bytes ein Fehler auftritt
-   */
-  public CombinedInputStream(InputStream[] input) throws IOException{
-    this.input = input;
-    regenerateAvailableBytes();
-  }
-
-  /**
-   * Erzeugt einen neuen <code>CombinedInputStream</code>.
-   * @param size Anzahl an Eingabe-Streams auf die der
-   *        <code>CombinedInputStream</code> dimensioniert wird
-   */
-  public CombinedInputStream(int size) {
-    this.input = new InputStream[size];
-  }
-
-  /**
-   * Liefert die Anzahl an Streams aus der der <code>CombinedInputStream</code>
-   * zusammengesetzt wurde.
-   */
-  public int getStreamCount() {
-    return input.length;
-  }
-
-  /**
-   * Setzt einen Teil-Stream. Die Anzahl der insgesamt zur Verfuegung stehenden
-   * Bytes wird danach neu berechnet.
-   * @see #regenerateAvailableBytes()
-   */
-  public void setInputStream(int i, InputStream stream) throws IOException {
-    this.input[i] = stream;
-    regenerateAvailableBytes();
-  }
-
-  /**
-   * Errechnet die Anzahl der insgesamt zur Verfuegung stehenden Bytes neu.
-   * Dabei werden nur der aktuelle Stream und die darauf folgenden beruecksichtigt.
-   * Die bereits ausgelesenen Streams werden ignoriert, auch wenn in ihnen
-   * nun evt. wieder Bytes zur Verfuegung stehen.
-   */
-  public void regenerateAvailableBytes() throws IOException {
-    avBytes = 0;
-    for (int i=actStream; i<input.length; i++)
-      if ( input[i] != null ) avBytes += input[i].available();
-  }
-
-  /**
-   * Liefert die gesamt Anzahl von Bytes, die in den Eingabe-Streams
-   * noch zur Verfuegung stehen.<br>
-   * <b>Bemerkung:</b><br>
-   * Aus Effizienzgruenden wird die Anzahl der Verfuegung stehenden Bytes
-   * nicht bei jedem Aufruf neu errechnet, sondern nur beim Setzen eines
-   * neuen Streams (mittels <code>setInputStream(..)</code>). Danach wird
-   * nach bei jedem <code>read()</code>-Aufruf ein Zaehler herabgesetzt.<br>
-   * Aendert sich die Byte-Zahl eines Teil-Streams waehrend der Benutzung des
-   * <code>CombinedInputStream</code>, sollte die Methode
-   * <code>regenerateAvailableBytes()</code> aufgerufen werden, um die Anzahl
-   * der zur Verfuegung stehenden Bytes neu zu berechnen!!
-   * @exception java.io.IOException falls der Zugriff auf einen der beiden
-   *            Eingabe-Streams scheitert
-   * @see #regenerateAvailableBytes()
-   */
-  public int available() {
-    return avBytes;
-  }
-
-  /**
-   * Liefert ein (unsigned) Byte aus dem aktuellen Stream.
-   * Solange der erste Stream noch Daten liefern kann, werden seine Bytes
-   * zurueckgegeben. Danach die Bytes des zweiten Streams, usw.
-   * @return -1, falls keiner der Streams noch Daten liefern kann
-   * @exception java.io.IOException falls der Zugriff auf einen der
-   *            Eingabe-Streams scheitert
-   * @see #available()
-   */
-  public int read() throws IOException {
-    while( actStream < input.length && input[actStream].available() < 1 ) actStream++;
-    if ( actStream >= input.length ) return -1;
-    avBytes--;
-    return input[actStream].read();
-  }
-
-  /**
-   * Schliesst alle Eingabe-Streams.
-   * @exception java.io.IOException falls der Zugriff auf einen der
-   *            Eingabe-Streams scheitert
-   */
-  public void close() throws IOException {
-    for (int i=0; i<input.length; i++) this.input[i].close();
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * <hr>
+ * <small><i>Diese Klasse wurde urspruenglich 2002/2003 von <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *            fuer die ADAGIOS-Java-Library (Universitaet Bonn) erstellt, 2009 in das
+ *            SCHMITZM-Projekt uebernommen und teilweise erweitert.</i></small>
+ * <hr>
+ * Diese Klasse stellt einen Eingabe-Stream dar, der Daten auf Basis
+ * mehrerer anderen <code>InputStream</code>-Instanzen liefert. Zunaechst
+ * werden Bytes aus dem ersten Stream geliefert, wenn dieser Stream keine
+ * Daten mehr liefern kann aus dem zweiten, usw.<br>
+ * Sobald ein Stream einmal komplett geleert wurde, liefert die
+ * <code>read()</code>-Methode nur noch Bytes aus einem der naechsten
+ * Streams. Auch wenn der "leere" Stream spaeter wieder Daten liefern koennte,
+ * werden diese nicht mehr beruecksichtigt, sondern einfach ignoriert.<br>
+ * Diese Klasse kann z.B. verwendet werden, um bereits aus einem InputStream
+ * gelesene Daten (z.B. einen Header) diesem wieder voranzustellen, um
+ * den InputStream "als Original" weiterzugeben.<br>
+ * <b><u>Beispiel</u>:</b><br>
+ * Ein Klasse liest Text-Repraesentationenen <u>unterschiedlicher</u> Typen
+ * aus einer Datei. Erst nachdem der Header eines jeden Objekts eingelesen
+ * wurde, kann entschieden werden, welche Typ-Klasse instanziiert werden muss.
+ * Um deren <code>initFromText(InputStream)</code>-Methode aufrufen zu koennen,
+ * wird aber wieder der komplette InputStream inklusive Header benoetigt.<br>
+ * Hierzu kann ein <code>CombinedInputStream</code>, zusammengesetzt aus einem
+ * neuen <code>ByteArrayInputStream</code> fuer den bereits eingelesenen
+ * Header und dem Eingabe-Stream der Datei, erzeugt werden, welcher der
+ * <code>initFromText(InputStream)</code>-Methode uebergeben wird.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class CombinedInputStream extends InputStream {
+  private InputStream[] input     = null;
+  private int           actStream = 0;
+  private int           avBytes   = 0;
+
+
+  /**
+   * Erzeugt einen neuen <code>CombinedInputStream</code>.
+   * @param input Eingabe-Streams aus denen sukzessive gelesen wird
+   * @exception java.io.IOException falls beim Ermitteln der insgesamt
+   *            zur Verfuegung stehenden Bytes ein Fehler auftritt
+   */
+  public CombinedInputStream(InputStream[] input) throws IOException{
+    this.input = input;
+    regenerateAvailableBytes();
+  }
+
+  /**
+   * Erzeugt einen neuen <code>CombinedInputStream</code>.
+   * @param size Anzahl an Eingabe-Streams auf die der
+   *        <code>CombinedInputStream</code> dimensioniert wird
+   */
+  public CombinedInputStream(int size) {
+    this.input = new InputStream[size];
+  }
+
+  /**
+   * Liefert die Anzahl an Streams aus der der <code>CombinedInputStream</code>
+   * zusammengesetzt wurde.
+   */
+  public int getStreamCount() {
+    return input.length;
+  }
+
+  /**
+   * Setzt einen Teil-Stream. Die Anzahl der insgesamt zur Verfuegung stehenden
+   * Bytes wird danach neu berechnet.
+   * @see #regenerateAvailableBytes()
+   */
+  public void setInputStream(int i, InputStream stream) throws IOException {
+    this.input[i] = stream;
+    regenerateAvailableBytes();
+  }
+
+  /**
+   * Errechnet die Anzahl der insgesamt zur Verfuegung stehenden Bytes neu.
+   * Dabei werden nur der aktuelle Stream und die darauf folgenden beruecksichtigt.
+   * Die bereits ausgelesenen Streams werden ignoriert, auch wenn in ihnen
+   * nun evt. wieder Bytes zur Verfuegung stehen.
+   */
+  public void regenerateAvailableBytes() throws IOException {
+    avBytes = 0;
+    for (int i=actStream; i<input.length; i++)
+      if ( input[i] != null ) avBytes += input[i].available();
+  }
+
+  /**
+   * Liefert die gesamt Anzahl von Bytes, die in den Eingabe-Streams
+   * noch zur Verfuegung stehen.<br>
+   * <b>Bemerkung:</b><br>
+   * Aus Effizienzgruenden wird die Anzahl der Verfuegung stehenden Bytes
+   * nicht bei jedem Aufruf neu errechnet, sondern nur beim Setzen eines
+   * neuen Streams (mittels <code>setInputStream(..)</code>). Danach wird
+   * nach bei jedem <code>read()</code>-Aufruf ein Zaehler herabgesetzt.<br>
+   * Aendert sich die Byte-Zahl eines Teil-Streams waehrend der Benutzung des
+   * <code>CombinedInputStream</code>, sollte die Methode
+   * <code>regenerateAvailableBytes()</code> aufgerufen werden, um die Anzahl
+   * der zur Verfuegung stehenden Bytes neu zu berechnen!!
+   * @exception java.io.IOException falls der Zugriff auf einen der beiden
+   *            Eingabe-Streams scheitert
+   * @see #regenerateAvailableBytes()
+   */
+  public int available() {
+    return avBytes;
+  }
+
+  /**
+   * Liefert ein (unsigned) Byte aus dem aktuellen Stream.
+   * Solange der erste Stream noch Daten liefern kann, werden seine Bytes
+   * zurueckgegeben. Danach die Bytes des zweiten Streams, usw.
+   * @return -1, falls keiner der Streams noch Daten liefern kann
+   * @exception java.io.IOException falls der Zugriff auf einen der
+   *            Eingabe-Streams scheitert
+   * @see #available()
+   */
+  public int read() throws IOException {
+    while( actStream < input.length && input[actStream].available() < 1 ) actStream++;
+    if ( actStream >= input.length ) return -1;
+    avBytes--;
+    return input[actStream].read();
+  }
+
+  /**
+   * Schliesst alle Eingabe-Streams.
+   * @exception java.io.IOException falls der Zugriff auf einen der
+   *            Eingabe-Streams scheitert
+   */
+  public void close() throws IOException {
+    for (int i=0; i<input.length; i++) this.input[i].close();
+  }
+
+}

Modified: trunk/src/schmitzm/io/FileInputStream.java
===================================================================
--- trunk/src/schmitzm/io/FileInputStream.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/io/FileInputStream.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,64 +1,82 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.io;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.io;
-
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
-
-/**
- * Diese Klasse erweitert den {@link java.io.FileInputStream} in der Art, dass
- * eine Referenz auf die zugrunde liegende Datei gespeichert wird. Diese kann
- * ueber {@link #getFile()} abgerufen werden.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class FileInputStream extends java.io.FileInputStream {
-  private File file = null;
-
-  /**
-   * Erzeugt einen neuen <code>FileInputStream</code>.<br>
-   * Siehe {@link java.io.FileInputStream#FileInputStream(File)}.
-   */
-  public FileInputStream(File file) throws FileNotFoundException {
-    super(file);
-    this.file = file;
-  }
-
-  /**
-   * Erzeugt einen neuen <code>FileInputStream</code>.<br>
-   * Siehe {@link java.io.FileInputStream#FileInputStream(String)}.
-   */
-  public FileInputStream(String name) throws FileNotFoundException {
-    super(name);
-    this.file = new File(name);
-  }
-
-  /**
-   * Erzeugt einen neuen <code>FileInputStream</code>.<br>
-   * Siehe {@link java.io.FileInputStream#FileInputStream(FileDescriptor)}.
-   */
-  public FileInputStream(FileDescriptor fdObj) throws FileNotFoundException {
-    super(fdObj);
-  }
-
-  /**
-   * Liefert die Datei, auf der der InputStream basiert.
-   * @return <code>null</code> falls der Stream auf einem <code>FileDescriptor</code>
-   *         basiert
-   * @return File
-   */
-  public File getFile() {
-    return file;
-  }
-
-}
+
+/**
+ * Diese Klasse erweitert den {@link java.io.FileInputStream} in der Art, dass
+ * eine Referenz auf die zugrunde liegende Datei gespeichert wird. Diese kann
+ * ueber {@link #getFile()} abgerufen werden.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class FileInputStream extends java.io.FileInputStream {
+  private File file = null;
+
+  /**
+   * Erzeugt einen neuen <code>FileInputStream</code>.<br>
+   * Siehe {@link java.io.FileInputStream#FileInputStream(File)}.
+   */
+  public FileInputStream(File file) throws FileNotFoundException {
+    super(file);
+    this.file = file;
+  }
+
+  /**
+   * Erzeugt einen neuen <code>FileInputStream</code>.<br>
+   * Siehe {@link java.io.FileInputStream#FileInputStream(String)}.
+   */
+  public FileInputStream(String name) throws FileNotFoundException {
+    super(name);
+    this.file = new File(name);
+  }
+
+  /**
+   * Erzeugt einen neuen <code>FileInputStream</code>.<br>
+   * Siehe {@link java.io.FileInputStream#FileInputStream(FileDescriptor)}.
+   */
+  public FileInputStream(FileDescriptor fdObj) throws FileNotFoundException {
+    super(fdObj);
+  }
+
+  /**
+   * Liefert die Datei, auf der der InputStream basiert.
+   * @return <code>null</code> falls der Stream auf einem <code>FileDescriptor</code>
+   *         basiert
+   * @return File
+   */
+  public File getFile() {
+    return file;
+  }
+
+}

Modified: trunk/src/schmitzm/io/FileOutputStream.java
===================================================================
--- trunk/src/schmitzm/io/FileOutputStream.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/io/FileOutputStream.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,82 +1,100 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.io;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.io;
-
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.FileNotFoundException;
-
-/**
- * Diese Klasse erweitert den {@link java.io.FileOutputStream} in der Art, dass
- * eine Referenz auf die zugrunde liegende Datei gespeichert wird. Diese kann
- * ueber {@link #getFile()} abgerufen werden.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class FileOutputStream extends java.io.FileOutputStream {
-  private File file = null;
-
-  /**
-   * Erzeugt einen neuen <code>FileOutputStream</code>.<br>
-   * Siehe {@link java.io.FileOutputStream#FileOutputStream(File)}.
-   */
-  public FileOutputStream(File file) throws FileNotFoundException {
-    super(file);
-    this.file = file;
-  }
-
-  /**
-   * Erzeugt einen neuen <code>FileOutputStream</code>.<br>
-   * Siehe {@link java.io.FileOutputStream#FileOutputStream(File,boolean)}.
-   */
-  public FileOutputStream(File file, boolean append) throws FileNotFoundException {
-    super(file,append);
-    this.file = file;
-  }
-
-  /**
-   * Erzeugt einen neuen <code>FileOutputStream</code>.<br>
-   * Siehe {@link java.io.FileOutputStream#FileOutputStream(FileDescriptor)}.
-   */
-  public FileOutputStream(FileDescriptor fdObj) throws FileNotFoundException {
-    super(fdObj);
-  }
-
-  /**
-   * Erzeugt einen neuen <code>FileOutputStream</code>.<br>
-   * Siehe {@link java.io.FileOutputStream#FileOutputStream(String)}.
-   */
-  public FileOutputStream(String name) throws FileNotFoundException {
-    super(name);
-    this.file = new File(name);
-  }
-
-  /**
-   * Erzeugt einen neuen <code>FileOutputStream</code>.<br>
-   * Siehe {@link java.io.FileOutputStream#FileOutputStream(String,boolean)}.
-   */
-  public FileOutputStream(String name, boolean append) throws FileNotFoundException {
-    super(name,append);
-    this.file = new File(name);
-  }
-
-
-  /**
-   * Liefert die Datei, auf der der OutputStream basiert.
-   * @return <code>null</code> falls der Stream auf einem <code>FileDescriptor</code>
-   *         basiert
-   * @return File
-   */
-  public File getFile() {
-    return file;
-  }
-}
+
+/**
+ * Diese Klasse erweitert den {@link java.io.FileOutputStream} in der Art, dass
+ * eine Referenz auf die zugrunde liegende Datei gespeichert wird. Diese kann
+ * ueber {@link #getFile()} abgerufen werden.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class FileOutputStream extends java.io.FileOutputStream {
+  private File file = null;
+
+  /**
+   * Erzeugt einen neuen <code>FileOutputStream</code>.<br>
+   * Siehe {@link java.io.FileOutputStream#FileOutputStream(File)}.
+   */
+  public FileOutputStream(File file) throws FileNotFoundException {
+    super(file);
+    this.file = file;
+  }
+
+  /**
+   * Erzeugt einen neuen <code>FileOutputStream</code>.<br>
+   * Siehe {@link java.io.FileOutputStream#FileOutputStream(File,boolean)}.
+   */
+  public FileOutputStream(File file, boolean append) throws FileNotFoundException {
+    super(file,append);
+    this.file = file;
+  }
+
+  /**
+   * Erzeugt einen neuen <code>FileOutputStream</code>.<br>
+   * Siehe {@link java.io.FileOutputStream#FileOutputStream(FileDescriptor)}.
+   */
+  public FileOutputStream(FileDescriptor fdObj) throws FileNotFoundException {
+    super(fdObj);
+  }
+
+  /**
+   * Erzeugt einen neuen <code>FileOutputStream</code>.<br>
+   * Siehe {@link java.io.FileOutputStream#FileOutputStream(String)}.
+   */
+  public FileOutputStream(String name) throws FileNotFoundException {
+    super(name);
+    this.file = new File(name);
+  }
+
+  /**
+   * Erzeugt einen neuen <code>FileOutputStream</code>.<br>
+   * Siehe {@link java.io.FileOutputStream#FileOutputStream(String,boolean)}.
+   */
+  public FileOutputStream(String name, boolean append) throws FileNotFoundException {
+    super(name,append);
+    this.file = new File(name);
+  }
+
+
+  /**
+   * Liefert die Datei, auf der der OutputStream basiert.
+   * @return <code>null</code> falls der Stream auf einem <code>FileDescriptor</code>
+   *         basiert
+   * @return File
+   */
+  public File getFile() {
+    return file;
+  }
+}

Modified: trunk/src/schmitzm/io/IOUtil.java
===================================================================
--- trunk/src/schmitzm/io/IOUtil.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/io/IOUtil.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,572 +1,590 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.io;
-
-import java.io.File;
-import java.io.FileFilter;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.net.MalformedURLException;
-import java.net.URL;
-
-import org.apache.log4j.Logger;
-
-/**
- * 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)
- *
- * @version 1.0
- */
-public class IOUtil {
-
-  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);
-
-  /**
-   * 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);
-
-    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(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
-   * @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;
-  }
-
-  /**
-   * 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>
-	 *
-	 * @return A new {@link URL} with new extension.
-	 *
-	 * @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{
-		String a = url.toExternalForm();
-                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);
-		}
-	}
-	
-
-	  /**
-	 * 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
-	 * {@link MalformedURLException} geworfen
-	 * 
-	 * @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();
-		final int lastDotPos = a.lastIndexOf('/');
-		if (lastDotPos >= 0)
-			a = a.substring(0, lastDotPos);
-		return new URL(a);
-	}
-
-
-
-  /**
-	 * @deprecated use getParentUrl()
-	 */
-	public static URL getParentURL(URL url) throws MalformedURLException {
-		return getParentUrl(url);
-	}
-
-	/**
-	 * 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 {
-		String a = base.toExternalForm();
-		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 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 );
-
-    // 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 );
-
-    // 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 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;
-  }
-
-  /**
-   * 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();
-  }
-
-  /**
-   * 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) ;
-        }
-      };
-    }
-
-    //##### 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) ;
-      }
-    };
-  }
-
-  /**
-   * 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() );
-        }
-        System.out.println(message);
-      }
-    }
-    // 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
-	 *      ://weblogs.java.net/blog/kohsuke/archive/2007/04/how_to_convert.html
-	 * 
-	 * @param url
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public static File urlToFile(URL url) {
-		LOGGER.debug("\nconverting " + url.toString() + " to ");
-		File f;
-		try {
-			f = new File(url.toURI());
-		} catch (Exception e) {
-			f = new File(url.getPath().replace("%20", " "));
-		}
-		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;
-	    }
-
-	    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);
-	      System.out.println(delCount+ " files deleted.");
-	    }
-	    else {
-	      LOGGER.error("Unknown function: "+func);
-	    }
-	  }
-
-	  /**
-	 * The method File getTempDir() caches the system's temp direcotry here.
-	 * 
-	 * @see #getTempDir()
-	 */
-	private static File tempDir;
-
-	/**
-	 * The system property <code>java.io.tmpdir</code> is not consistent on
-	 * Linux and Windows. On Windows&Solaris the path ends with a slash, on
-	 * Linux&MacOS it doesn't. This method deals with this potential pit-fall.<br/>
-	 * 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}
-	 * 
-	 * @see
-	 *      <code>http://rationalpi.wordpress.com/2007/01/26/javaiotmpdir-inconsitency/</code>
-	 */
-	public static File getTempDir() {
-
-		if (tempDir == null) {
-			String tempPath = System.getProperty("java.io.tmpdir", System
-					.getenv("TEMP"));
-
-			if (tempPath == null || tempPath.isEmpty() || !new File(tempPath).exists()) {
-				LOGGER.warn("Temporary directory can't be found. Using /tmp");
-				tempPath = "/tmp";
-			}
-
-			while (tempPath.endsWith(File.separator))
-				tempPath = tempPath.substring(0, tempPath.length() - 1);
-
-			tempDir = new File(tempPath);
-			
-			if (!tempDir.exists()) throw new IllegalStateException("Temp direcotory can't be determined."); 
-		}
-
-		return tempDir;
-	}
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.io;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.apache.log4j.Logger;
+
+/**
+ * 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)
+ *
+ * @version 1.0
+ */
+public class IOUtil {
+
+  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);
+
+  /**
+   * 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);
+
+    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(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
+   * @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;
+  }
+
+  /**
+   * 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>
+	 *
+	 * @return A new {@link URL} with new extension.
+	 *
+	 * @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{
+		String a = url.toExternalForm();
+                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);
+		}
+	}
+	
+
+	  /**
+	 * 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
+	 * {@link MalformedURLException} geworfen
+	 * 
+	 * @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();
+		final int lastDotPos = a.lastIndexOf('/');
+		if (lastDotPos >= 0)
+			a = a.substring(0, lastDotPos);
+		return new URL(a);
+	}
+
+
+
+  /**
+	 * @deprecated use getParentUrl()
+	 */
+	public static URL getParentURL(URL url) throws MalformedURLException {
+		return getParentUrl(url);
+	}
+
+	/**
+	 * 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 {
+		String a = base.toExternalForm();
+		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 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 );
+
+    // 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 );
+
+    // 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 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;
+  }
+
+  /**
+   * 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();
+  }
+
+  /**
+   * 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) ;
+        }
+      };
+    }
+
+    //##### 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) ;
+      }
+    };
+  }
+
+  /**
+   * 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() );
+        }
+        System.out.println(message);
+      }
+    }
+    // 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
+	 *      ://weblogs.java.net/blog/kohsuke/archive/2007/04/how_to_convert.html
+	 * 
+	 * @param url
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public static File urlToFile(URL url) {
+		LOGGER.debug("\nconverting " + url.toString() + " to ");
+		File f;
+		try {
+			f = new File(url.toURI());
+		} catch (Exception e) {
+			f = new File(url.getPath().replace("%20", " "));
+		}
+		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;
+	    }
+
+	    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);
+	      System.out.println(delCount+ " files deleted.");
+	    }
+	    else {
+	      LOGGER.error("Unknown function: "+func);
+	    }
+	  }
+
+	  /**
+	 * The method File getTempDir() caches the system's temp direcotry here.
+	 * 
+	 * @see #getTempDir()
+	 */
+	private static File tempDir;
+
+	/**
+	 * The system property <code>java.io.tmpdir</code> is not consistent on
+	 * Linux and Windows. On Windows&Solaris the path ends with a slash, on
+	 * Linux&MacOS it doesn't. This method deals with this potential pit-fall.<br/>
+	 * 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}
+	 * 
+	 * @see
+	 *      <code>http://rationalpi.wordpress.com/2007/01/26/javaiotmpdir-inconsitency/</code>
+	 */
+	public static File getTempDir() {
+
+		if (tempDir == null) {
+			String tempPath = System.getProperty("java.io.tmpdir", System
+					.getenv("TEMP"));
+
+			if (tempPath == null || tempPath.isEmpty() || !new File(tempPath).exists()) {
+				LOGGER.warn("Temporary directory can't be found. Using /tmp");
+				tempPath = "/tmp";
+			}
+
+			while (tempPath.endsWith(File.separator))
+				tempPath = tempPath.substring(0, tempPath.length() - 1);
+
+			tempDir = new File(tempPath);
+			
+			if (!tempDir.exists()) throw new IllegalStateException("Temp direcotory can't be determined."); 
+		}
+
+		return tempDir;
+	}
+
+}

Modified: trunk/src/schmitzm/io/InputBuffer.java
===================================================================
--- trunk/src/schmitzm/io/InputBuffer.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/io/InputBuffer.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,187 +1,205 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.io;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * <hr>
- * <small><i>Diese Klasse wurde urspruenglich 2002/2003 von <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- *            fuer die ADAGIOS-Java-Library (Universitaet Bonn) erstellt, 2009 in das
- *            SCHMITZM-Projekt uebernommen und teilweise erweitert.</i></small>
- * <hr>
- * Diese Klasse stellt einen InputStream dar, der sukzessive Bytes
- * aus einem Buffer liefert. Dieser Buffer kann permanent wieder
- * (auf)gefuellt werden. Dazu muss er nicht erst komplett geleert
- * worden sein!<br>
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class InputBuffer extends InputStream {
-  protected byte[]  buffer      = null;
-  protected int     readPos     = 0;
-  protected int     writePos    = 0;
-  protected boolean bufferFull  = false;
-
-  /**
-   * Erzeugt einen neuen <code>InputBuffer</code>.
-   * @param byteSize Groesse des Buffers in Byte
-   */
-  public InputBuffer(int byteSize) {
-    buffer = new byte[byteSize];
-  }
-
-  public int getBufferSize() {
-    return buffer.length;
-  }
-
-  /**
-   * Erhoeht die Zeiger-Position im Buffer. Ist das Ende des Buffers
-   * erreicht, springt der Zeiger wieder auf die Position 0.
-   */
-  protected int incPosition(int pos) {
-    return incPosition(pos,1);
-  }
-
-  /**
-   * Erhoeht die Zeiger-Position im Buffer. Ist das Ende des Buffers
-   * erreicht, springt der Zeiger wieder nach vorne.
-   * @param pos aktuelle Zeiger-Position
-   * @param hop Anzahl an Positionen, die vor gerueckt werden sollen
-   */
-  protected int incPosition(int pos, int hop) {
-    pos += hop;
-    return pos % getBufferSize();
-  }
-
-  /**
-   * Schreibt ein Byte in den Buffer.
-   * @param b ein Byte
-   * @exception java.nio.BufferOverflowException falls der Buffer bereits voll ist
-   */
-  public void write(byte b) {
-    if ( availableSpace() == 0 )
-      throw new java.nio.BufferOverflowException();
-    buffer[writePos] = b;
-    // Schreib-Zeiger erhoehen
-    writePos = incPosition(writePos);
-    // wenn Schreib-Zeiger nun auf der aktuellen Lese-Position
-    // steht, ist der Buffer voll
-    bufferFull = ( writePos == readPos );
-  }
-
-  /**
-   * Schreibt eine Reihe von Bytes in den Buffer.
-   * @param bytes Menge von zu schreibenen Bytes
-   * @exception java.nio.BufferOverflowException falls der Buffer bereits voll ist
-   */
-  public void write(byte[] bytes) {
-    for (int i=0; i<bytes.length; i++)
-      write(bytes[i]);
-  }
-
-  /**
-   * Schreibt eine Reihe von Bytes in den Buffer. Diese Methode blockiert,
-   * bis der InputStream die geforderte Anzahl an Bytes liefern kann.
-   * @param input  Stream aus dem die Bytes gelesen werden
-   * @param len    Anzahl zu lesender Bytes
-   * @exception java.nio.BufferOverflowException falls nicht genuegend freier
-   *            Platz im Buffer ist
-   * @exception java.io.IOException falls das Lesen aus dem Eingabe-Stream
-   *            scheitert
-   */
-  public void write(InputStream input, int len) throws IOException {
-    if ( availableSpace() < len )
-      throw new java.nio.BufferOverflowException();
-
-    // Ist zwischen dem Schreib-Cursor und dem Buffer-Ende noch genug
-    // Platz, koennen alle Bytes AN EINEM STUECK gespeichert werden
-    if ( writePos + len-1 < getBufferSize() ) {
-      input.read(buffer,writePos,len);
-      incPosition(writePos,len);
-      bufferFull = ( writePos == readPos );
-    }
-    else {
-      // Ansonsten wird erst bis zum Buffer-Ende geschrieben
-      int len1 = getBufferSize()-writePos;
-      write(input, len1);
-      // Nachdem dann der Cursor wieder am Anfang des Buffers
-      // steht, wird der Rest an einem Stueck geschrieben
-      write(input, len - len1);
-    }
-  }
-
-  /**
-   * Liefert die Anzahl an Bytes, die (noch) in den Buffer
-   * geschrieben werden koennen.
-   */
-  public int availableSpace() {
-    return Math.abs( getBufferSize() - available() );
-  }
-
-  /**
-   * Liesst das naechste Byte aus dem Buffer. Der zurueckgelieferte
-   * Wert liegt zwischen 0 und 255.
-   * @return -1 falls der Buffer leer ist
-   */
-  public int read() throws IOException {
-    if ( available() == 0 ) return -1;
-    int b = BinaryUtil.getUnsignedByte( buffer[readPos] );
-    readPos = incPosition(readPos);
-    // Buffer hat auf jeden Fall jetzt wieder einen freien Platz
-    bufferFull = false;
-    return b;
-  }
-
-  /**
-   * Liefert die Anzahl an Bytes, die (noch) aus dem Buffer
-   * gelesen werden koennen.
-   */
-  public int available() {
-    // wenn der Buffer voll ist, ist writePos = readPos
-    // --> available() wuerde jedoch 0 liefern
-    if ( bufferFull ) return getBufferSize();
-    return ( writePos - readPos + getBufferSize() ) % getBufferSize();
-  }
-
-  /**
-   * Entfernt eine Anzahl von Bytes aus dem Buffer. Liegen nicht mehr
-   * genug Bytes im Buffer, wird dies ignoriert und der Buffer einfach
-   * komplett geleert.
-   * @param n Anzahl zu entfernender Bytes (muss ein <code>int</code> sein)
-   * @return Anzahl an Bytes, die aus dem Buffer entfernt wurden
-   */
-  public long skip(long n) {
-    int skipped = Math.min((int)n,available());
-    readPos = incPosition(readPos,skipped);
-    return skipped;
-  }
-
-  /**
-   * Leert den Buffer.
-   * @return Anzahl an Bytes, die noch im Buffer waren
-   */
-  public long clear() {
-    return skip( this.available() );
-  }
-
-  /**
-   * Liefert den aktuellen Inhalt des Buffers als <code>bytes</code>-Array.
-   */
-  public byte[] getContent() {
-    byte[] buf = new byte[available()];
-    for (int i=0; i<buf.length; i++)
-      buf[i] = buffer[ (readPos+i)%buffer.length ];
-    return buf;
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * <hr>
+ * <small><i>Diese Klasse wurde urspruenglich 2002/2003 von <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *            fuer die ADAGIOS-Java-Library (Universitaet Bonn) erstellt, 2009 in das
+ *            SCHMITZM-Projekt uebernommen und teilweise erweitert.</i></small>
+ * <hr>
+ * Diese Klasse stellt einen InputStream dar, der sukzessive Bytes
+ * aus einem Buffer liefert. Dieser Buffer kann permanent wieder
+ * (auf)gefuellt werden. Dazu muss er nicht erst komplett geleert
+ * worden sein!<br>
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class InputBuffer extends InputStream {
+  protected byte[]  buffer      = null;
+  protected int     readPos     = 0;
+  protected int     writePos    = 0;
+  protected boolean bufferFull  = false;
+
+  /**
+   * Erzeugt einen neuen <code>InputBuffer</code>.
+   * @param byteSize Groesse des Buffers in Byte
+   */
+  public InputBuffer(int byteSize) {
+    buffer = new byte[byteSize];
+  }
+
+  public int getBufferSize() {
+    return buffer.length;
+  }
+
+  /**
+   * Erhoeht die Zeiger-Position im Buffer. Ist das Ende des Buffers
+   * erreicht, springt der Zeiger wieder auf die Position 0.
+   */
+  protected int incPosition(int pos) {
+    return incPosition(pos,1);
+  }
+
+  /**
+   * Erhoeht die Zeiger-Position im Buffer. Ist das Ende des Buffers
+   * erreicht, springt der Zeiger wieder nach vorne.
+   * @param pos aktuelle Zeiger-Position
+   * @param hop Anzahl an Positionen, die vor gerueckt werden sollen
+   */
+  protected int incPosition(int pos, int hop) {
+    pos += hop;
+    return pos % getBufferSize();
+  }
+
+  /**
+   * Schreibt ein Byte in den Buffer.
+   * @param b ein Byte
+   * @exception java.nio.BufferOverflowException falls der Buffer bereits voll ist
+   */
+  public void write(byte b) {
+    if ( availableSpace() == 0 )
+      throw new java.nio.BufferOverflowException();
+    buffer[writePos] = b;
+    // Schreib-Zeiger erhoehen
+    writePos = incPosition(writePos);
+    // wenn Schreib-Zeiger nun auf der aktuellen Lese-Position
+    // steht, ist der Buffer voll
+    bufferFull = ( writePos == readPos );
+  }
+
+  /**
+   * Schreibt eine Reihe von Bytes in den Buffer.
+   * @param bytes Menge von zu schreibenen Bytes
+   * @exception java.nio.BufferOverflowException falls der Buffer bereits voll ist
+   */
+  public void write(byte[] bytes) {
+    for (int i=0; i<bytes.length; i++)
+      write(bytes[i]);
+  }
+
+  /**
+   * Schreibt eine Reihe von Bytes in den Buffer. Diese Methode blockiert,
+   * bis der InputStream die geforderte Anzahl an Bytes liefern kann.
+   * @param input  Stream aus dem die Bytes gelesen werden
+   * @param len    Anzahl zu lesender Bytes
+   * @exception java.nio.BufferOverflowException falls nicht genuegend freier
+   *            Platz im Buffer ist
+   * @exception java.io.IOException falls das Lesen aus dem Eingabe-Stream
+   *            scheitert
+   */
+  public void write(InputStream input, int len) throws IOException {
+    if ( availableSpace() < len )
+      throw new java.nio.BufferOverflowException();
+
+    // Ist zwischen dem Schreib-Cursor und dem Buffer-Ende noch genug
+    // Platz, koennen alle Bytes AN EINEM STUECK gespeichert werden
+    if ( writePos + len-1 < getBufferSize() ) {
+      input.read(buffer,writePos,len);
+      incPosition(writePos,len);
+      bufferFull = ( writePos == readPos );
+    }
+    else {
+      // Ansonsten wird erst bis zum Buffer-Ende geschrieben
+      int len1 = getBufferSize()-writePos;
+      write(input, len1);
+      // Nachdem dann der Cursor wieder am Anfang des Buffers
+      // steht, wird der Rest an einem Stueck geschrieben
+      write(input, len - len1);
+    }
+  }
+
+  /**
+   * Liefert die Anzahl an Bytes, die (noch) in den Buffer
+   * geschrieben werden koennen.
+   */
+  public int availableSpace() {
+    return Math.abs( getBufferSize() - available() );
+  }
+
+  /**
+   * Liesst das naechste Byte aus dem Buffer. Der zurueckgelieferte
+   * Wert liegt zwischen 0 und 255.
+   * @return -1 falls der Buffer leer ist
+   */
+  public int read() throws IOException {
+    if ( available() == 0 ) return -1;
+    int b = BinaryUtil.getUnsignedByte( buffer[readPos] );
+    readPos = incPosition(readPos);
+    // Buffer hat auf jeden Fall jetzt wieder einen freien Platz
+    bufferFull = false;
+    return b;
+  }
+
+  /**
+   * Liefert die Anzahl an Bytes, die (noch) aus dem Buffer
+   * gelesen werden koennen.
+   */
+  public int available() {
+    // wenn der Buffer voll ist, ist writePos = readPos
+    // --> available() wuerde jedoch 0 liefern
+    if ( bufferFull ) return getBufferSize();
+    return ( writePos - readPos + getBufferSize() ) % getBufferSize();
+  }
+
+  /**
+   * Entfernt eine Anzahl von Bytes aus dem Buffer. Liegen nicht mehr
+   * genug Bytes im Buffer, wird dies ignoriert und der Buffer einfach
+   * komplett geleert.
+   * @param n Anzahl zu entfernender Bytes (muss ein <code>int</code> sein)
+   * @return Anzahl an Bytes, die aus dem Buffer entfernt wurden
+   */
+  public long skip(long n) {
+    int skipped = Math.min((int)n,available());
+    readPos = incPosition(readPos,skipped);
+    return skipped;
+  }
+
+  /**
+   * Leert den Buffer.
+   * @return Anzahl an Bytes, die noch im Buffer waren
+   */
+  public long clear() {
+    return skip( this.available() );
+  }
+
+  /**
+   * Liefert den aktuellen Inhalt des Buffers als <code>bytes</code>-Array.
+   */
+  public byte[] getContent() {
+    byte[] buf = new byte[available()];
+    for (int i=0; i<buf.length; i++)
+      buf[i] = buffer[ (readPos+i)%buffer.length ];
+    return buf;
+  }
+}

Modified: trunk/src/schmitzm/io/LimitedInputStream.java
===================================================================
--- trunk/src/schmitzm/io/LimitedInputStream.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/io/LimitedInputStream.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,98 +1,117 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.io;
-
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * <hr>
- * <small><i>Diese Klasse wurde urspruenglich 2002/2003 von <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- *            fuer die ADAGIOS-Java-Library (Universitaet Bonn) erstellt, 2009 in das
- *            SCHMITZM-Projekt uebernommen und teilweise erweitert.</i></small>
- * <hr>
- * Diese Klasse repraesentiert einen Eingabe-Stream, der einen anderen
- * Eingabe-Stream kapselt und auf eine bestimmte Groesse begrenzt.
- * Somit ist es moeglich, einer Methode "vorzugaukeln" der ihr uebergebene
- * InputStream habe eine bestimmte Laenge, obwohl er in Wirklichkeit viel
- * groesser ist.<br>
- * Der Leser fragt sich nach dem Sinn? :-)<br>
- * <b>Beispiel:</b><br>
- * In einem InputStream A stehen nacheinander die Binaer-Repraesentationen
- * geometrischer Objekte. Die ersten N Bytes gehoeren zum ersten Objekt.<br>
- * Uebergibt man nun den gesamten Stream an die <code>initFromBinary</code>-Methode,
- * wuerde diese u.U. nicht nur die ersten N Bytes lesen, sondern versuchen,
- * den kompletten Stream als Objekt zu interpretieren!!<br>
- * Uebergibt man der <code>initFromBinary</code>-Methode jedoch einen
- * <code>LimitedInputStream</code> der auf dem Stream A basiert und auf N
- * Bytes begrenzt ist, sind die restlichen Bytes von A (die hinter dem N-ten
- * Byte stehen) fuer die <code>initFromBinary</code>-Methode transparent.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class LimitedInputStream extends InputStream {
-  private InputStream input;
-  private int         limit;
-  private int         readCount;
-
-  /**
-   * Erzeugt einen neuen <code>LimitedInputStream</code>.
-   * @param input Basis-Daten
-   * @param limit Maximale Anzahl an Bytes, die aus dem Basis-Stream gelesen
-   *              werden, bevor der <code>LimitedInputStream</code> sein
-   *              Ende erreicht
-   */
-  public LimitedInputStream(InputStream input, int limit) {
-    this.input     = input;
-    this.readCount = 0;
-    setLimit(limit);
-  }
-
-  /**
-   * Liefert das Limit fuer den Stream.
-   */
-  public int getLimit() {
-    return limit;
-  }
-
-  /**
-   * Setzt das Limit fuer den Stream.
-   * @param limit neues Limit (in Bytes)
-   * @exception java.lang.IllegalArgumentException falls <code>limit < 0</code>
-   */
-  public void setLimit(int limit) {
-    if ( limit < 0 )
-      throw new IllegalArgumentException("Limit must be greater or equal 0");
-    this.limit = limit;
-  }
-
-  /**
-   * Liefert die Anzahl an Bytes, die noch aus dem <code>LimitedInputStream</code>
-   * gelesen werden koennen.
-   * @exception java.io.IOException falls der <code>available()</code>-Aufruf
-   *            fuer den Basis-Stream scheitert
-   */
-  public int available() throws IOException {
-    return Math.min(input.available(),Math.max(limit-readCount,0));
-  }
-
-  /**
-   * Liefert ein Byte des Basis-Streams, solange das Limit (oder das Ende
-   * des Basis-Stream) noch nicht erreicht ist.
-   * @exception java.io.IOException falls der <code>read()</code>-Aufruf
-   *            fuer den Basis-Stream scheitert
-   */
-  public int read() throws IOException {
-    if ( available() <= 0 ) return -1;
-    readCount++;
-    return input.read();
-  }
-}
\ No newline at end of file
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * <hr>
+ * <small><i>Diese Klasse wurde urspruenglich 2002/2003 von <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *            fuer die ADAGIOS-Java-Library (Universitaet Bonn) erstellt, 2009 in das
+ *            SCHMITZM-Projekt uebernommen und teilweise erweitert.</i></small>
+ * <hr>
+ * Diese Klasse repraesentiert einen Eingabe-Stream, der einen anderen
+ * Eingabe-Stream kapselt und auf eine bestimmte Groesse begrenzt.
+ * Somit ist es moeglich, einer Methode "vorzugaukeln" der ihr uebergebene
+ * InputStream habe eine bestimmte Laenge, obwohl er in Wirklichkeit viel
+ * groesser ist.<br>
+ * Der Leser fragt sich nach dem Sinn? :-)<br>
+ * <b>Beispiel:</b><br>
+ * In einem InputStream A stehen nacheinander die Binaer-Repraesentationen
+ * geometrischer Objekte. Die ersten N Bytes gehoeren zum ersten Objekt.<br>
+ * Uebergibt man nun den gesamten Stream an die <code>initFromBinary</code>-Methode,
+ * wuerde diese u.U. nicht nur die ersten N Bytes lesen, sondern versuchen,
+ * den kompletten Stream als Objekt zu interpretieren!!<br>
+ * Uebergibt man der <code>initFromBinary</code>-Methode jedoch einen
+ * <code>LimitedInputStream</code> der auf dem Stream A basiert und auf N
+ * Bytes begrenzt ist, sind die restlichen Bytes von A (die hinter dem N-ten
+ * Byte stehen) fuer die <code>initFromBinary</code>-Methode transparent.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class LimitedInputStream extends InputStream {
+  private InputStream input;
+  private int         limit;
+  private int         readCount;
+
+  /**
+   * Erzeugt einen neuen <code>LimitedInputStream</code>.
+   * @param input Basis-Daten
+   * @param limit Maximale Anzahl an Bytes, die aus dem Basis-Stream gelesen
+   *              werden, bevor der <code>LimitedInputStream</code> sein
+   *              Ende erreicht
+   */
+  public LimitedInputStream(InputStream input, int limit) {
+    this.input     = input;
+    this.readCount = 0;
+    setLimit(limit);
+  }
+
+  /**
+   * Liefert das Limit fuer den Stream.
+   */
+  public int getLimit() {
+    return limit;
+  }
+
+  /**
+   * Setzt das Limit fuer den Stream.
+   * @param limit neues Limit (in Bytes)
+   * @exception java.lang.IllegalArgumentException falls <code>limit < 0</code>
+   */
+  public void setLimit(int limit) {
+    if ( limit < 0 )
+      throw new IllegalArgumentException("Limit must be greater or equal 0");
+    this.limit = limit;
+  }
+
+  /**
+   * Liefert die Anzahl an Bytes, die noch aus dem <code>LimitedInputStream</code>
+   * gelesen werden koennen.
+   * @exception java.io.IOException falls der <code>available()</code>-Aufruf
+   *            fuer den Basis-Stream scheitert
+   */
+  public int available() throws IOException {
+    return Math.min(input.available(),Math.max(limit-readCount,0));
+  }
+
+  /**
+   * Liefert ein Byte des Basis-Streams, solange das Limit (oder das Ende
+   * des Basis-Stream) noch nicht erreicht ist.
+   * @exception java.io.IOException falls der <code>read()</code>-Aufruf
+   *            fuer den Basis-Stream scheitert
+   */
+  public int read() throws IOException {
+    if ( available() <= 0 ) return -1;
+    readCount++;
+    return input.read();
+  }
+}

Modified: trunk/src/schmitzm/io/TokenInputStream.java
===================================================================
--- trunk/src/schmitzm/io/TokenInputStream.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/io/TokenInputStream.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,353 +1,372 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.io;
-
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.PushbackInputStream;
-import java.io.StreamTokenizer;
-
-/**
- * <hr>
- * <small><i>Diese Klasse wurde urspruenglich 2002/2003 von <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- *            fuer die ADAGIOS-Java-Library (Universitaet Bonn) erstellt, 2009 in das
- *            SCHMITZM-Projekt uebernommen und teilweise erweitert.</i></small>
- * <hr>
- * Diese Klasse erweitert einen <code>DataInputStream</code> um die
- * Eigenschaft des <code>StreamTokenizer</code>
- * @see java.io.StreamTokenizer
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-
-public class TokenInputStream extends PushbackInputStream {
-  /**
-   * Instanz von <code>DefaultTokenDefinition</code>.
-   * @see adagios.types.TokenInputStream.DefaultTokenDefinition
-   */
-  public static final TokenDefinition DEFAULT_TOKENDEF = new DefaultTokenDefinition();
-
-
-  /**
-   * Signalisiert, dass kein Token mehr gelesen werden konnte, da
-   * das Ende des Basisstreams erreicht wurde.
-   * @see java.io.StreamTokenizer#TT_EOF
-   */
-  public static final int TT_EOF = StreamTokenizer.TT_EOF;
-
-  /**
-   * Signalisiert, dass das gelesene Token numerisch ist und
-   * in <code>nval</code> gespeichert ist.
-   * @see java.io.StreamTokenizer#TT_NUMBER
-   */
-  public static final int TT_NUMBER = StreamTokenizer.TT_NUMBER;
-
-  /**
-   * Signalisiert, dass das gelesene Token alphanumerisch ist und
-   * in <code>sval</code> gespeichert ist.
-   * @see java.io.StreamTokenizer#TT_WORD
-   */
-  public static final int TT_WORD = StreamTokenizer.TT_WORD;
-
-  /**
-   * Enthaelt den Typ des letzten gelesenene Tokens.
-   * @see #TT_EOF
-   * @see #TT_NUMBER
-   * @see #TT_WORD
-   * @see java.io.StreamTokenizer#ttype
-   */
-  public int    ttype = 0;
-
-  /**
-   * Handelt es sich bei dem letzten Token um eine Zeichenkette, wird diese
-   * in <code>sval</code> gespeichtert. Ansonsten ist <code>sval = null</code>.
-   * @see java.io.StreamTokenizer#sval
-   */
-  public String sval  = null;
-
-  /**
-   * Handelt es sich bei dem letzten Token um einen numerischen Wert, wird dieser
-   * in <code>nval</code> gespeichtert. Ansonsten ist <code>nval = 0.0</code>.
-   * @see java.io.StreamTokenizer#nval
-   */
-  public double nval  = 0.0;
-
-  private TokenDefinition def = new DefaultTokenDefinition();
-
-  /**
-   * Erzeugt einen neuen TokenInputStream.
-   * Der Pushback-Buffer wird mit 64Byte initialisiert. Als Tokendefinition wird
-   * <code>DefaultTokenDefinition</code> verwendet.
-   * @param is BasisInputStream
-   * @see #DEFAULT_TOKENDEF
-   */
-  public TokenInputStream(InputStream is) {
-    this(is,64);
-  }
-
-  /**
-   * Erzeugt einen neuen TokenInputStream. Als Tokendefinition wird
-   * <code>DefaultTokenDefinition</code> verwendet.
-   * @param is   BasisInputStream
-   * @param size Groesse des Pushback-Buffers
-   * @exception java.lang.IllegalArgumentException falls <code>size <= 0</code>
-   * @see #DEFAULT_TOKENDEF
-   */
-  public TokenInputStream(InputStream is, int size) {
-    this(is,size,DEFAULT_TOKENDEF);
-  }
-
-  /**
-   * Erzeugt einen neuen TokenInputStream.
-   * @param is   BasisInputStream
-   * @param size Groesse des Pushback-Buffers
-   * @param def  bestimmt wie die Token aufgebaut sind
-   * @exception java.lang.IllegalArgumentException falls <code>size <= 0</code>
-   * @see adagios.types.TokenInputStream.TokenDefinition
-   * @see #DEFAULT_TOKENDEF
-   */
-  public TokenInputStream(InputStream is, int size, TokenDefinition def) {
-    super(is,size);
-    this.def = def;
-  }
-
-  /**
-   * Liefert einen neuen <code>TokenInputStream</code>.
-   * Handelt es sich bei dem uebergebenen Basis-Stream bereits um einen
-   * <code>TokenInputStream</code> wird dieser (gecastet) zurueckgeliefert,
-   * ansonsten wird eine neue Instanz erzeugt.
-   * @param is Basis-Stream
-   */
-  public static TokenInputStream fromInputStream(InputStream is) {
-    if ( is instanceof TokenInputStream )
-      return (TokenInputStream)is;
-    return new TokenInputStream(is);
-  }
-
-  /**
-   * Liefert die zugrunde liegende Token-Definition.
-   */
-  public TokenDefinition getTokenDefinition() {
-    return def;
-  }
-
-  /**
-   * Liesst ein Token vom Stream. Dabei werden zunaecht alle Delimiter-Zeichen
-   * aus dem Stream gelesen und ignoriert.
-   * Das erste Nicht-Delimiter-Zeichen bestimmt, ob das Token numerisch ist,
-   * oder nicht. Bei numerischen Tokens wird das "Token-Lesen" beim ersten
-   * nicht-numerischen Zeichen abgebrochen. Bei nicht-numerische Tokens erst
-   * beim naechsten Delimiter.<br>
-   * Der Wert des Tokens wird der Variablen <code>sval</code> oder
-   * <code>nval</code> hinterlegt.<br>
-   * Ein (nicht-numerisches) Ein-Zeichen-Token wird direkt als <code>int</code>
-   * im Attribut <code>ttype</code> gespeichert und nicht in <code>sval</code>
-   * (vgl. <code>StreamTokenizer</code>).<br>
-   * <b>Beispiel (Delimiter = " \n\t"):</b><br>
-   * <code>"   abcd456bla   999.99k k88 9,88   "</code> liefert die Token<br>
-   * <ul>
-   * <li><code>sval  = "abcd456bla"</code></li>
-   * <li><code>nval  = 999.99</code></li>
-   * <li><code>sval  = "k"</code></li>
-   * <li><code>sval  = "k88"</code></li>
-   * <li><code>nval  = 9.0</code></li>
-   * <li><code>ttype = ','</code></li>
-   * <li><code>nval  = 88.0</code></li>
-   * </ul>
-   * @return Typ des Tokens (Inhalt von <code>ttype</code>)
-   * @see #ttype
-   * @see #sval
-   * @see #nval
-   * @see StreamTokenizer#ttype
-   * @see StreamTokenizer#nextToken()
-   */
-  public int readToken() throws IOException {
-    char         c            = 999;
-    StringBuffer token        = new StringBuffer();
-
-    // Stream bereits zu Ende
-    if ( available() <= 0 )
-      return determineGlobalVariables("");
-
-    // alle Delimiter-Chars ignorieren
-    while ( available()>0 && def.isDelimiter( c = (char)read() ) );
-    // wenn das letzte gelesene Zeichen ein Delimiter war ist der Stream zu Ende,
-    // ohne dass ein Token gelesen werden kann
-    if ( def.isDelimiter(c) )
-      return determineGlobalVariables("");
-
-    // letztes gelesenes Zeichen gehoert bereits zum Token
-    token.append(c);
-
-    boolean numericToken = false;
-    // handelt es sich um ein Single-Character, wird nicht weitergelesen
-    if ( !def.isSingleChar(c) ) {
-      // ob das Token numerisch ist, bestimmt das erste Zeichen
-      numericToken = def.isNumericStarter(c);
-      // alle Zeichen dem Token hinzufuegen, bis ein Delimiter, ein SingleChar
-      // oder bei numerischen Tokens ein nicht-numerisches Zeichen erreicht wird
-      while ( available()>0 && !def.isDelimiter( c = (char)read() )
-                            && !def.isSingleChar( c )
-                            && (!numericToken || def.isNumeric(c)) ) {
-        token.append(c);
-      }
-      // letztes gelesenes Zeichen ist ein Delimiter oder ein Zeichen, dass
-      // nicht zum Token "passt"
-      // --> dieses muss zurueck auf den Stream
-      unread(c);
-    }
-//    System.err.println("-> "+token.toString());
-
-    return determineGlobalVariables(token.toString());
-  }
-
-  /**
-   * Legt das letzte Token zurueck auf den Stream. Wiederholte Aufrufe legen
-   * das letzte Token mehrmals zurueck auf den Stream!!
-   * Die Methode wird ignoriert, falls den letze Aufruf von
-   * <code>nextToken(..)</code> das Streamende ueberschritten hat.
-   * @return <code>false</code>, falls das letzte Token nicht auf den Stream
-   *         zurueckgelegt werden konnte
-   * @exception java.io.IOException falls das Zuruecklegen der Bytes auf den
-   *            BasisStream scheitert
-   */
-  public boolean pushBack() throws IOException {
-    byte[] b = null;
-    switch (ttype) {
-      case StreamTokenizer.TT_NUMBER: // numerisches Token
-                                      b = String.valueOf(nval).getBytes();
-                                      break;
-      case StreamTokenizer.TT_WORD: // alphanumerisches Token
-                                    b = sval.getBytes();
-                                    break;
-      case StreamTokenizer.TT_EOL: // Token kann nicht rekonstruiert werden
-      case StreamTokenizer.TT_EOF: return false;
-      default: // ein Zeichen
-               b = new byte[] { (byte)ttype };
-    }
-
-    unread(b);
-    return true;
-  }
-
-  /**
-   * Bestimmt den Typ des Tokens (Char, numerisch, alphanumerisch) und
-   * belegt entsprechend die globalen Variablen.
-   * @return neuer Wert von <code>ttype</code>
-   */
-  private int determineGlobalVariables(String token) {
-    // keine Nicht-Delimiter mehr auf dem Stream
-    if (token.length() == 0)
-      return setGlobalVariables(StreamTokenizer.TT_EOF, null, 0.0);
-
-    // ein Ein-Zeichen-Token wird als int im Typ-Feld gespeichert
-    if ( token.length() == 1 && def.isSingleChar(token.charAt(0)) )
-      return setGlobalVariables(token.charAt(0),null,0.0);
-
-    try {
-      // versuchen, dass Token in eine Zahl umzuwandeln
-      return setGlobalVariables(StreamTokenizer.TT_NUMBER,null,Double.parseDouble(token));
-    }
-    catch (Exception err) {
-      // scheitert der Versuch, dass Token in eine Zahl umzuwandeln, handelt
-      // es sich bei dem Token um eine Zeichenkette
-      return setGlobalVariables(StreamTokenizer.TT_WORD,token,0.0);
-    }
-  }
-
-  /**
-   * Belegt die globalen Variablen mit den angegebenen Werten.
-   * @return neuer Wert von <code>ttype</code>
-   */
-  private int setGlobalVariables(int ttype, String sval, double nval) {
-    this.ttype = ttype;
-    this.sval  = sval;
-    this.nval  = nval;
-    return ttype;
-  }
-
-  /**
-   * Diese Klasse bestimmt, wie die Zeichen in einem <code>TokenInputStream</code>
-   * zu Token zusammengefasst werde.
-   */
-  public static interface TokenDefinition {
-    /**
-     * Bestimmt, welche Zeichen "Delimiter" sind. Delimiter-Zeichen trennen
-     * Token voneinander und werden ignoriert.
-     */
-    public boolean isDelimiter(char c);
-
-    /**
-     * Bestimmt, welche Zeichen numerisch sind.<br>
-     * z.B. 0 bis 9 und '.'
-     */
-    public boolean isNumeric(char c);
-
-    /**
-     * Bestimmt, welche Zeichen ein numerisches Token einleiten. Im
-     * Gegensatz zu <code>isNumeric(..)</code> sollten z.B. keine
-     * Kommas oder Punkte als "NumericStarter" deklariert werden.<br>
-     * z.B. 0 bis 9
-     */
-    public boolean isNumericStarter(char c);
-
-    /**
-     * Bestimmt, ob ein Zeichen ein "Einzelnes Zeichen" ist. SingleChars werden
-     * werden nicht zu Token zusammengefasst, sondern immer als eigenes
-     * Token behandelt. SingleChars trennen also auch Token voneinander.
-     */
-    public boolean isSingleChar(char c);
-  }
-
-  /**
-   * Diese Klasse stellt eine Standard-Definition fuer einen
-   * <code>TokenInputStream</code> dar.
-   * @see adagios.types.TokenInputStream
-   * @see adagios.types.TokenInputStream.TokenDefinition
-   */
-  public static class DefaultTokenDefinition implements TokenDefinition {
-    /**
-     * Delimiter sind SPACE ' ', TAB '\t' und CR '\n'.
-     */
-    public boolean isDelimiter(char c) {
-      return c == ' '   // SPACE
-          || c == '\t'  // TAB
-          || c == '\n'; // CR
-    }
-
-    /**
-     * Numerische Token muessen mit '0'..'9' oder '-' beginnen.
-     */
-    public boolean isNumericStarter(char c) {
-      return c >= '0' && c <= '9' || c == '-';
-    }
-
-    /**
-     * Numerische Zeichen sind NumericStarter oder Punkt.
-     */
-    public boolean isNumeric(char c) {
-      return isNumericStarter(c) || c == '.';
-    }
-
-    /**
-     * SingleChars sind Komma, Semikolon, Plus, Minus, Gleich, Slash,
-     * BackSlash, Doppelpunkt, Pipe, runde Klammern, eckige Klammern und
-     * geschweifte Klammern.
-     */
-    public boolean isSingleChar(char c) {
-      return c == ',' || c == ';'
-          || c == '+'  || c == '=' || c == '/'
-          || c == ':' || c == '\\' || c == '|'
-          || c == '(' || c == ')'  || c == '[' || c == ']'
-          || c == '{' || c == '}';
-    }
-  }
-}
\ No newline at end of file
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.io;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.PushbackInputStream;
+import java.io.StreamTokenizer;
+
+/**
+ * <hr>
+ * <small><i>Diese Klasse wurde urspruenglich 2002/2003 von <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *            fuer die ADAGIOS-Java-Library (Universitaet Bonn) erstellt, 2009 in das
+ *            SCHMITZM-Projekt uebernommen und teilweise erweitert.</i></small>
+ * <hr>
+ * Diese Klasse erweitert einen <code>DataInputStream</code> um die
+ * Eigenschaft des <code>StreamTokenizer</code>
+ * @see java.io.StreamTokenizer
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+
+public class TokenInputStream extends PushbackInputStream {
+  /**
+   * Instanz von <code>DefaultTokenDefinition</code>.
+   * @see adagios.types.TokenInputStream.DefaultTokenDefinition
+   */
+  public static final TokenDefinition DEFAULT_TOKENDEF = new DefaultTokenDefinition();
+
+
+  /**
+   * Signalisiert, dass kein Token mehr gelesen werden konnte, da
+   * das Ende des Basisstreams erreicht wurde.
+   * @see java.io.StreamTokenizer#TT_EOF
+   */
+  public static final int TT_EOF = StreamTokenizer.TT_EOF;
+
+  /**
+   * Signalisiert, dass das gelesene Token numerisch ist und
+   * in <code>nval</code> gespeichert ist.
+   * @see java.io.StreamTokenizer#TT_NUMBER
+   */
+  public static final int TT_NUMBER = StreamTokenizer.TT_NUMBER;
+
+  /**
+   * Signalisiert, dass das gelesene Token alphanumerisch ist und
+   * in <code>sval</code> gespeichert ist.
+   * @see java.io.StreamTokenizer#TT_WORD
+   */
+  public static final int TT_WORD = StreamTokenizer.TT_WORD;
+
+  /**
+   * Enthaelt den Typ des letzten gelesenene Tokens.
+   * @see #TT_EOF
+   * @see #TT_NUMBER
+   * @see #TT_WORD
+   * @see java.io.StreamTokenizer#ttype
+   */
+  public int    ttype = 0;
+
+  /**
+   * Handelt es sich bei dem letzten Token um eine Zeichenkette, wird diese
+   * in <code>sval</code> gespeichtert. Ansonsten ist <code>sval = null</code>.
+   * @see java.io.StreamTokenizer#sval
+   */
+  public String sval  = null;
+
+  /**
+   * Handelt es sich bei dem letzten Token um einen numerischen Wert, wird dieser
+   * in <code>nval</code> gespeichtert. Ansonsten ist <code>nval = 0.0</code>.
+   * @see java.io.StreamTokenizer#nval
+   */
+  public double nval  = 0.0;
+
+  private TokenDefinition def = new DefaultTokenDefinition();
+
+  /**
+   * Erzeugt einen neuen TokenInputStream.
+   * Der Pushback-Buffer wird mit 64Byte initialisiert. Als Tokendefinition wird
+   * <code>DefaultTokenDefinition</code> verwendet.
+   * @param is BasisInputStream
+   * @see #DEFAULT_TOKENDEF
+   */
+  public TokenInputStream(InputStream is) {
+    this(is,64);
+  }
+
+  /**
+   * Erzeugt einen neuen TokenInputStream. Als Tokendefinition wird
+   * <code>DefaultTokenDefinition</code> verwendet.
+   * @param is   BasisInputStream
+   * @param size Groesse des Pushback-Buffers
+   * @exception java.lang.IllegalArgumentException falls <code>size <= 0</code>
+   * @see #DEFAULT_TOKENDEF
+   */
+  public TokenInputStream(InputStream is, int size) {
+    this(is,size,DEFAULT_TOKENDEF);
+  }
+
+  /**
+   * Erzeugt einen neuen TokenInputStream.
+   * @param is   BasisInputStream
+   * @param size Groesse des Pushback-Buffers
+   * @param def  bestimmt wie die Token aufgebaut sind
+   * @exception java.lang.IllegalArgumentException falls <code>size <= 0</code>
+   * @see adagios.types.TokenInputStream.TokenDefinition
+   * @see #DEFAULT_TOKENDEF
+   */
+  public TokenInputStream(InputStream is, int size, TokenDefinition def) {
+    super(is,size);
+    this.def = def;
+  }
+
+  /**
+   * Liefert einen neuen <code>TokenInputStream</code>.
+   * Handelt es sich bei dem uebergebenen Basis-Stream bereits um einen
+   * <code>TokenInputStream</code> wird dieser (gecastet) zurueckgeliefert,
+   * ansonsten wird eine neue Instanz erzeugt.
+   * @param is Basis-Stream
+   */
+  public static TokenInputStream fromInputStream(InputStream is) {
+    if ( is instanceof TokenInputStream )
+      return (TokenInputStream)is;
+    return new TokenInputStream(is);
+  }
+
+  /**
+   * Liefert die zugrunde liegende Token-Definition.
+   */
+  public TokenDefinition getTokenDefinition() {
+    return def;
+  }
+
+  /**
+   * Liesst ein Token vom Stream. Dabei werden zunaecht alle Delimiter-Zeichen
+   * aus dem Stream gelesen und ignoriert.
+   * Das erste Nicht-Delimiter-Zeichen bestimmt, ob das Token numerisch ist,
+   * oder nicht. Bei numerischen Tokens wird das "Token-Lesen" beim ersten
+   * nicht-numerischen Zeichen abgebrochen. Bei nicht-numerische Tokens erst
+   * beim naechsten Delimiter.<br>
+   * Der Wert des Tokens wird der Variablen <code>sval</code> oder
+   * <code>nval</code> hinterlegt.<br>
+   * Ein (nicht-numerisches) Ein-Zeichen-Token wird direkt als <code>int</code>
+   * im Attribut <code>ttype</code> gespeichert und nicht in <code>sval</code>
+   * (vgl. <code>StreamTokenizer</code>).<br>
+   * <b>Beispiel (Delimiter = " \n\t"):</b><br>
+   * <code>"   abcd456bla   999.99k k88 9,88   "</code> liefert die Token<br>
+   * <ul>
+   * <li><code>sval  = "abcd456bla"</code></li>
+   * <li><code>nval  = 999.99</code></li>
+   * <li><code>sval  = "k"</code></li>
+   * <li><code>sval  = "k88"</code></li>
+   * <li><code>nval  = 9.0</code></li>
+   * <li><code>ttype = ','</code></li>
+   * <li><code>nval  = 88.0</code></li>
+   * </ul>
+   * @return Typ des Tokens (Inhalt von <code>ttype</code>)
+   * @see #ttype
+   * @see #sval
+   * @see #nval
+   * @see StreamTokenizer#ttype
+   * @see StreamTokenizer#nextToken()
+   */
+  public int readToken() throws IOException {
+    char         c            = 999;
+    StringBuffer token        = new StringBuffer();
+
+    // Stream bereits zu Ende
+    if ( available() <= 0 )
+      return determineGlobalVariables("");
+
+    // alle Delimiter-Chars ignorieren
+    while ( available()>0 && def.isDelimiter( c = (char)read() ) );
+    // wenn das letzte gelesene Zeichen ein Delimiter war ist der Stream zu Ende,
+    // ohne dass ein Token gelesen werden kann
+    if ( def.isDelimiter(c) )
+      return determineGlobalVariables("");
+
+    // letztes gelesenes Zeichen gehoert bereits zum Token
+    token.append(c);
+
+    boolean numericToken = false;
+    // handelt es sich um ein Single-Character, wird nicht weitergelesen
+    if ( !def.isSingleChar(c) ) {
+      // ob das Token numerisch ist, bestimmt das erste Zeichen
+      numericToken = def.isNumericStarter(c);
+      // alle Zeichen dem Token hinzufuegen, bis ein Delimiter, ein SingleChar
+      // oder bei numerischen Tokens ein nicht-numerisches Zeichen erreicht wird
+      while ( available()>0 && !def.isDelimiter( c = (char)read() )
+                            && !def.isSingleChar( c )
+                            && (!numericToken || def.isNumeric(c)) ) {
+        token.append(c);
+      }
+      // letztes gelesenes Zeichen ist ein Delimiter oder ein Zeichen, dass
+      // nicht zum Token "passt"
+      // --> dieses muss zurueck auf den Stream
+      unread(c);
+    }
+//    System.err.println("-> "+token.toString());
+
+    return determineGlobalVariables(token.toString());
+  }
+
+  /**
+   * Legt das letzte Token zurueck auf den Stream. Wiederholte Aufrufe legen
+   * das letzte Token mehrmals zurueck auf den Stream!!
+   * Die Methode wird ignoriert, falls den letze Aufruf von
+   * <code>nextToken(..)</code> das Streamende ueberschritten hat.
+   * @return <code>false</code>, falls das letzte Token nicht auf den Stream
+   *         zurueckgelegt werden konnte
+   * @exception java.io.IOException falls das Zuruecklegen der Bytes auf den
+   *            BasisStream scheitert
+   */
+  public boolean pushBack() throws IOException {
+    byte[] b = null;
+    switch (ttype) {
+      case StreamTokenizer.TT_NUMBER: // numerisches Token
+                                      b = String.valueOf(nval).getBytes();
+                                      break;
+      case StreamTokenizer.TT_WORD: // alphanumerisches Token
+                                    b = sval.getBytes();
+                                    break;
+      case StreamTokenizer.TT_EOL: // Token kann nicht rekonstruiert werden
+      case StreamTokenizer.TT_EOF: return false;
+      default: // ein Zeichen
+               b = new byte[] { (byte)ttype };
+    }
+
+    unread(b);
+    return true;
+  }
+
+  /**
+   * Bestimmt den Typ des Tokens (Char, numerisch, alphanumerisch) und
+   * belegt entsprechend die globalen Variablen.
+   * @return neuer Wert von <code>ttype</code>
+   */
+  private int determineGlobalVariables(String token) {
+    // keine Nicht-Delimiter mehr auf dem Stream
+    if (token.length() == 0)
+      return setGlobalVariables(StreamTokenizer.TT_EOF, null, 0.0);
+
+    // ein Ein-Zeichen-Token wird als int im Typ-Feld gespeichert
+    if ( token.length() == 1 && def.isSingleChar(token.charAt(0)) )
+      return setGlobalVariables(token.charAt(0),null,0.0);
+
+    try {
+      // versuchen, dass Token in eine Zahl umzuwandeln
+      return setGlobalVariables(StreamTokenizer.TT_NUMBER,null,Double.parseDouble(token));
+    }
+    catch (Exception err) {
+      // scheitert der Versuch, dass Token in eine Zahl umzuwandeln, handelt
+      // es sich bei dem Token um eine Zeichenkette
+      return setGlobalVariables(StreamTokenizer.TT_WORD,token,0.0);
+    }
+  }
+
+  /**
+   * Belegt die globalen Variablen mit den angegebenen Werten.
+   * @return neuer Wert von <code>ttype</code>
+   */
+  private int setGlobalVariables(int ttype, String sval, double nval) {
+    this.ttype = ttype;
+    this.sval  = sval;
+    this.nval  = nval;
+    return ttype;
+  }
+
+  /**
+   * Diese Klasse bestimmt, wie die Zeichen in einem <code>TokenInputStream</code>
+   * zu Token zusammengefasst werde.
+   */
+  public static interface TokenDefinition {
+    /**
+     * Bestimmt, welche Zeichen "Delimiter" sind. Delimiter-Zeichen trennen
+     * Token voneinander und werden ignoriert.
+     */
+    public boolean isDelimiter(char c);
+
+    /**
+     * Bestimmt, welche Zeichen numerisch sind.<br>
+     * z.B. 0 bis 9 und '.'
+     */
+    public boolean isNumeric(char c);
+
+    /**
+     * Bestimmt, welche Zeichen ein numerisches Token einleiten. Im
+     * Gegensatz zu <code>isNumeric(..)</code> sollten z.B. keine
+     * Kommas oder Punkte als "NumericStarter" deklariert werden.<br>
+     * z.B. 0 bis 9
+     */
+    public boolean isNumericStarter(char c);
+
+    /**
+     * Bestimmt, ob ein Zeichen ein "Einzelnes Zeichen" ist. SingleChars werden
+     * werden nicht zu Token zusammengefasst, sondern immer als eigenes
+     * Token behandelt. SingleChars trennen also auch Token voneinander.
+     */
+    public boolean isSingleChar(char c);
+  }
+
+  /**
+   * Diese Klasse stellt eine Standard-Definition fuer einen
+   * <code>TokenInputStream</code> dar.
+   * @see adagios.types.TokenInputStream
+   * @see adagios.types.TokenInputStream.TokenDefinition
+   */
+  public static class DefaultTokenDefinition implements TokenDefinition {
+    /**
+     * Delimiter sind SPACE ' ', TAB '\t' und CR '\n'.
+     */
+    public boolean isDelimiter(char c) {
+      return c == ' '   // SPACE
+          || c == '\t'  // TAB
+          || c == '\n'; // CR
+    }
+
+    /**
+     * Numerische Token muessen mit '0'..'9' oder '-' beginnen.
+     */
+    public boolean isNumericStarter(char c) {
+      return c >= '0' && c <= '9' || c == '-';
+    }
+
+    /**
+     * Numerische Zeichen sind NumericStarter oder Punkt.
+     */
+    public boolean isNumeric(char c) {
+      return isNumericStarter(c) || c == '.';
+    }
+
+    /**
+     * SingleChars sind Komma, Semikolon, Plus, Minus, Gleich, Slash,
+     * BackSlash, Doppelpunkt, Pipe, runde Klammern, eckige Klammern und
+     * geschweifte Klammern.
+     */
+    public boolean isSingleChar(char c) {
+      return c == ',' || c == ';'
+          || c == '+'  || c == '=' || c == '/'
+          || c == ':' || c == '\\' || c == '|'
+          || c == '(' || c == ')'  || c == '[' || c == ']'
+          || c == '{' || c == '}';
+    }
+  }
+}

Modified: trunk/src/schmitzm/io/dyntxt/DynamicBlock.java
===================================================================
--- trunk/src/schmitzm/io/dyntxt/DynamicBlock.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/io/dyntxt/DynamicBlock.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,14 +1,32 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package schmitzm.io.dyntxt;
 
 import java.io.IOException;
@@ -90,4 +108,4 @@
     for (int i=0; i<elements.size(); i++)
       ((DynamicElement)elements.elementAt(i)).performElement(inputProvider, output);
   }
-}
\ No newline at end of file
+}

Modified: trunk/src/schmitzm/io/dyntxt/DynamicElement.java
===================================================================
--- trunk/src/schmitzm/io/dyntxt/DynamicElement.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/io/dyntxt/DynamicElement.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,14 +1,32 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package schmitzm.io.dyntxt;
 
 import java.io.IOException;

Modified: trunk/src/schmitzm/io/dyntxt/DynamicField.java
===================================================================
--- trunk/src/schmitzm/io/dyntxt/DynamicField.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/io/dyntxt/DynamicField.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,14 +1,32 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package schmitzm.io.dyntxt;
 
 import java.io.IOException;

Modified: trunk/src/schmitzm/io/dyntxt/DynamicInputProvider.java
===================================================================
--- trunk/src/schmitzm/io/dyntxt/DynamicInputProvider.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/io/dyntxt/DynamicInputProvider.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,14 +1,32 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package schmitzm.io.dyntxt;
 
 /**

Modified: trunk/src/schmitzm/io/dyntxt/DynamicLoop.java
===================================================================
--- trunk/src/schmitzm/io/dyntxt/DynamicLoop.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/io/dyntxt/DynamicLoop.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,14 +1,32 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package schmitzm.io.dyntxt;
 
 import java.io.IOException;
@@ -64,4 +82,4 @@
     for (this.loopNo=0; inputProvider.performLoop(this); loopNo++)
       super.performElement(inputProvider,output);
   }
-}
\ No newline at end of file
+}

Modified: trunk/src/schmitzm/io/dyntxt/DynamicTextGenerator.java
===================================================================
--- trunk/src/schmitzm/io/dyntxt/DynamicTextGenerator.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/io/dyntxt/DynamicTextGenerator.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,14 +1,32 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package schmitzm.io.dyntxt;
 
 import java.io.BufferedReader;

Modified: trunk/src/schmitzm/io/dyntxt/StaticText.java
===================================================================
--- trunk/src/schmitzm/io/dyntxt/StaticText.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/io/dyntxt/StaticText.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,14 +1,32 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package schmitzm.io.dyntxt;
 
 import java.io.IOException;
@@ -70,4 +88,4 @@
   public void performElement(DynamicInputProvider inputProvider, OutputStream output) throws IOException {
     output.write( getText().getBytes() );
   }
-}
\ No newline at end of file
+}

Modified: trunk/src/schmitzm/jfree/DatasetMetaDataGroup.java
===================================================================
--- trunk/src/schmitzm/jfree/DatasetMetaDataGroup.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/DatasetMetaDataGroup.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,59 +1,77 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.jfree;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.jfree.data.general.Dataset;
-import org.jfree.data.general.DatasetGroup;
-
-/**
- * This {@link DatasetGroup} is raped! It provides the possibility to add
- * individual meta to a {@link Dataset}.
- * Because a {@link DatasetGroup} can be set to <b>every</b> {@link Dataset}, the
- * mata data can be accessed everywhere the {@link Dataset} can be accessed,
- * independently of the concrete {@link Dataset}.<br>
- * <b>Note:</b><br>
- * If a "real" {@link DatasetGroup} is set for a {@link Dataset}, the meta data
- * is lost!!
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- */
-public class DatasetMetaDataGroup extends DatasetGroup {
-  /** Holds meta data objects. */
-  protected Map<String,Object> metadata = new HashMap<String, Object>();
-
-  /**
-   * Creates a new meta data object.
-   */
-  public DatasetMetaDataGroup() {
-    super("METADATA");
-  }
-
-  /**
-   * Sets some meta data.
-   * @param metadataKey    a key for the meta data object
-   * @param metadataObject the meta data
-   */
-  public void setMetaData(String metadataKey, Object metadataObject) {
-    metadata.put(metadataKey, metadataObject);
-  }
-  
-  /**
-   * Returns some meta data.
-   * @param metadataKey  the key of the meta data
-   */
-  public Object getMetaData(String metadataKey) {
-    return metadata.get(metadataKey);
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.jfree;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.jfree.data.general.Dataset;
+import org.jfree.data.general.DatasetGroup;
+
+/**
+ * This {@link DatasetGroup} is raped! It provides the possibility to add
+ * individual meta to a {@link Dataset}.
+ * Because a {@link DatasetGroup} can be set to <b>every</b> {@link Dataset}, the
+ * mata data can be accessed everywhere the {@link Dataset} can be accessed,
+ * independently of the concrete {@link Dataset}.<br>
+ * <b>Note:</b><br>
+ * If a "real" {@link DatasetGroup} is set for a {@link Dataset}, the meta data
+ * is lost!!
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ */
+public class DatasetMetaDataGroup extends DatasetGroup {
+  /** Holds meta data objects. */
+  protected Map<String,Object> metadata = new HashMap<String, Object>();
+
+  /**
+   * Creates a new meta data object.
+   */
+  public DatasetMetaDataGroup() {
+    super("METADATA");
+  }
+
+  /**
+   * Sets some meta data.
+   * @param metadataKey    a key for the meta data object
+   * @param metadataObject the meta data
+   */
+  public void setMetaData(String metadataKey, Object metadataObject) {
+    metadata.put(metadataKey, metadataObject);
+  }
+  
+  /**
+   * Returns some meta data.
+   * @param metadataKey  the key of the meta data
+   */
+  public Object getMetaData(String metadataKey) {
+    return metadata.get(metadataKey);
+  }
+
+}

Modified: trunk/src/schmitzm/jfree/JFreeChartUtil.java
===================================================================
--- trunk/src/schmitzm/jfree/JFreeChartUtil.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/JFreeChartUtil.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,475 +1,494 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.jfree;
-
-import java.awt.Color;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Locale;
-
-import org.apache.log4j.Logger;
-import org.geotools.feature.AttributeType;
-import org.geotools.feature.Feature;
-import org.geotools.feature.FeatureCollection;
-import org.geotools.feature.FeatureIterator;
-import org.jfree.chart.JFreeChart;
-import org.jfree.chart.axis.NumberAxis;
-import org.jfree.chart.event.PlotChangeEvent;
-import org.jfree.chart.event.PlotChangeListener;
-import org.jfree.chart.event.RendererChangeEvent;
-import org.jfree.chart.event.RendererChangeListener;
-import org.jfree.chart.labels.StandardXYToolTipGenerator;
-import org.jfree.chart.labels.XYToolTipGenerator;
-import org.jfree.chart.plot.Plot;
-import org.jfree.chart.plot.PlotOrientation;
-import org.jfree.chart.plot.XYPlot;
-import org.jfree.chart.renderer.AbstractRenderer;
-import org.jfree.chart.renderer.category.AreaRenderer;
-import org.jfree.chart.renderer.category.BarRenderer;
-import org.jfree.chart.renderer.category.CategoryItemRenderer;
-import org.jfree.chart.renderer.category.CategoryStepRenderer;
-import org.jfree.chart.renderer.category.LineAndShapeRenderer;
-import org.jfree.chart.renderer.category.StackedAreaRenderer;
-import org.jfree.chart.renderer.category.StackedBarRenderer;
-import org.jfree.chart.renderer.xy.StackedXYAreaRenderer2;
-import org.jfree.chart.renderer.xy.StackedXYBarRenderer;
-import org.jfree.chart.renderer.xy.XYAreaRenderer;
-import org.jfree.chart.renderer.xy.XYBarRenderer;
-import org.jfree.chart.renderer.xy.XYItemRenderer;
-import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
-import org.jfree.chart.renderer.xy.XYStepAreaRenderer;
-import org.jfree.chart.renderer.xy.XYStepRenderer;
-import org.jfree.chart.title.LegendTitle;
-import org.jfree.chart.title.Title;
-import org.jfree.chart.urls.StandardXYURLGenerator;
-import org.jfree.chart.urls.XYURLGenerator;
-import org.jfree.data.function.Function2D;
-import org.jfree.data.function.LineFunction2D;
-import org.jfree.data.general.DatasetUtilities;
-import org.jfree.data.statistics.Regression;
-import org.jfree.data.xy.XYDataset;
-import org.jfree.data.xy.XYSeries;
-import org.jfree.data.xy.XYSeriesCollection;
-
-import schmitzm.jfree.chart.renderer.SelectionXYLineAndShapeRenderer;
-import schmitzm.jfree.chart.selection.DatasetSelectionModel;
-import schmitzm.jfree.chart.selection.DatasetSelectionModelProvider;
-import schmitzm.jfree.chart.style.BasicChartStyle;
-import schmitzm.jfree.chart.style.ChartStyle;
-import schmitzm.jfree.chart.style.ChartStyleXMLFactory;
-import schmitzm.jfree.chart.style.ChartType;
-import schmitzm.jfree.feature.Feature2SeriesDatasetMapping;
-import schmitzm.jfree.feature.FeatureDatasetMetaData;
-import schmitzm.jfree.feature.FeatureDatasetSelectionModel;
-import schmitzm.jfree.feature.FeatureSeriesDatasetSelectionModel;
-import schmitzm.lang.LangUtil;
-import schmitzm.lang.ResourceProvider;
-
-/**
- * In dieser Klasse sind Hilfsmethoden fuer JFreeChart hinterlegt.
- * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class JFreeChartUtil {
-  private static Logger LOGGER = Logger.getLogger(JFreeChartUtil.class.getName());
-  
-  /** {@link ResourceProvider}, der die Lokalisation fuer GUI-Komponenten
-   *  zur Verfuegung stellt. Diese sind in properties-Datein unter
-   *  {@code schmitzm.jfree.resource.locales.JFreeResourceBundle_XXX.properties}
-   *  hinterlegt. */
-  public static ResourceProvider RESOURCE = new ResourceProvider( LangUtil.extendPackagePath(JFreeChartUtil.class,"resource.locales.JFreeResourceBundle"), Locale.ENGLISH );
-
-	/**
-	 * Convenience method to access the {@link ResourceProvider}.
-	*/
-	public static String R(String key, Object... values) {
-		return RESOURCE.getString(key, values);
-	}
-
-  /** Instance of {@link ChartStyleXMLFactory}. */
-  public static final ChartStyleXMLFactory<ChartStyle> CHART_STYLE_FACTORY = new ChartStyleXMLFactory<ChartStyle>();
-
-  /**
-   * Sets all chart legends (in)visible.
-   * @param chart   a chart to apply
-   * @param visible indicates the visible property
-   */
-  public static void setLegendVisible(JFreeChart chart, boolean visible) {
-    for (Object title : chart.getSubtitles())
-      if ( title instanceof LegendTitle )
-        ((Title)title).setVisible(visible);
-  }
-  
-  /**
-   * Fires a change event to all {@link PlotChangeListener} connected
-   * to the plot. 
-   * @param plot a plot
-   */
-  public static void fireChangeEvent(Plot plot) {
-    plot.notifyListeners( new PlotChangeEvent(plot) );
-  }
-  
-  /**
-   * Fires a change event to all {@link RendererChangeListener} connected
-   * to the renderer. 
-   * @param renderer a renderer
-   */
-  public static void fireChangeEvent(AbstractRenderer renderer) {
-    renderer.notifyListeners( new RendererChangeEvent(renderer) );
-  }
-
-  /**
-   * Creates a {@link XYItemRenderer} for the given stepped and stacked
-   * properties.
-   * @param type    chart type
-   * @param stepped stepped property
-   * @param stacked stacked property
-   */
-  public static XYItemRenderer createXYRenderer(BasicChartStyle style) {
-    return createXYRenderer(
-        style.getType(),
-        style.isStepped(),
-        style.isStacked()
-    );
-  }
-  
-  /**
-   * Creates a {@link XYItemRenderer} for the given stepped and stacked
-   * properties.
-   * @param type    chart type
-   * @param stepped stepped property
-   * @param stacked stacked property
-   */
-  public static XYItemRenderer createXYRenderer(ChartType type, boolean stepped, boolean stacked) {
-    switch ( type ) {
-      case LINE: // "stacked" is not available for line charts
-                 if ( stacked )
-                   LOGGER.warn("Stacked property can not be applied to line charts. Property ignored!");
-                 // Create renderer according to "stepped"
-                 if ( stepped )
-                   return new XYStepRenderer();
-                 // normal line renderer
-                 return new XYLineAndShapeRenderer(true, false);
-      case AREA: // Apply stacked
-                 if ( stacked ) {
-                   // "stacked" and "stepped" can not be applied the same time
-                   if ( stepped )
-                     LOGGER.warn("A stacked area chart can not be stepped the same time (use a stacked bar chart instead). Stepped propery ignored!");
-                   // Stacked area renderer
-                   return new StackedXYAreaRenderer2();
-                 }
-                 // Stepped area renderer
-                 if ( stepped )
-                   return new XYStepAreaRenderer(XYStepAreaRenderer.AREA);
-                 // Neither stepped nor stepped
-                 return new XYAreaRenderer(XYAreaRenderer.AREA);
-      case BAR: // bar charts are automatically stepped,
-                // so only "stacked" is applied
-                if ( stacked )
-                  return new StackedXYBarRenderer();
-                // Normal bar renderer
-                return new XYBarRenderer();
-    }
-    throw new UnsupportedOperationException("XYItemRenderer could not be created for chart type: "+type); 
-  }
-
-  
-  /**
-   * Creates a {@link CategoryItemRenderer} for the given stepped and stacked
-   * properties.
-   * @param type    chart type
-   * @param stepped stepped property
-   * @param stacked stacked property
-   */
-  public static CategoryItemRenderer createCategoryRenderer(BasicChartStyle style) {
-    return createCategoryRenderer(
-        style.getType(),
-        style.isStepped(),
-        style.isStacked()
-    );
-  }
-  
-  /**
-   * Creates a {@link CategoryItemRenderer} for the given stepped and stacked
-   * properties.
-   * @param type    chart type
-   * @param stepped stepped property
-   * @param stacked stacked property
-   */
-  public static CategoryItemRenderer createCategoryRenderer(ChartType type, boolean stepped, boolean stacked) {
-    switch ( type ) {
-      case LINE: // "stacked" is not available for line charts
-                 if ( stacked )
-                   LOGGER.warn("Stacked property can not be applied to line charts. Property ignored!");
-                 // Create renderer according to "stepped"
-                 if ( stepped )
-                   return new CategoryStepRenderer();
-                 // normal line renderer
-                 return new LineAndShapeRenderer(true, false);
-      case AREA: // category area chart is automatically stepped,
-                 // so only "stacked" is applied
-                 if ( stacked )
-                   return new StackedAreaRenderer(false);
-                 // Normal area renderer
-                 return new AreaRenderer();
-      case BAR: // bar charts are automatically stepped,
-                // so only "stacked" is applied
-                if ( stacked )
-                  return new StackedBarRenderer(false);
-                // Normal bar renderer
-                return new BarRenderer();
-    }
-    throw new UnsupportedOperationException("CategoryItemRenderer could not be created for chart type: "+type); 
-  }
-
-  /**
-   * Creates a {@link XYDataset} for 2 attributes of a {@link FeatureCollection}.
-   * @param fc    a {@link FeatureCollection}
-   * @param seriesKey   a (unique) key for the {@link XYSeries} in the dataset
-   * @param xAttr feature attribute used for the X-value
-   * @param yAttr feature attribute used for the Y-value
-   */
-  public static XYSeriesCollection createXYDataset(FeatureCollection fc, String seriesKey, String xAttr, String yAttr) {
-    // check data types of X- and Y-column
-    AttributeType xType = fc.getSchema().getAttributeType(xAttr);
-    if ( xType == null )
-      throw new UnsupportedOperationException("Unknown attribute: "+xAttr);
-    AttributeType yType = fc.getSchema().getAttributeType(yAttr);
-    if ( yType == null )
-      throw new UnsupportedOperationException("Unknown attribute: "+yAttr);
-    if ( !Number.class.isAssignableFrom(xType.getBinding()) )
-      throw new UnsupportedOperationException("Attribute must be numeric: "+xAttr);
-    if ( !Number.class.isAssignableFrom(yType.getBinding()) )
-      throw new UnsupportedOperationException("Attribute must be numeric: "+yAttr);
-    
-    
-    XYSeriesCollection           dataset   = new XYSeriesCollection();
-    Feature2SeriesDatasetMapping mapping   = new Feature2SeriesDatasetMapping(fc,dataset);
-    FeatureIterator              fi        = fc.features();
-    XYSeries                     xySeries  = new XYSeries(seriesKey,false,true);
-    dataset.addSeries(xySeries);
-    dataset.setGroup( new FeatureDatasetMetaData(mapping) );
-    for (int i=0; fi.hasNext(); i++) {
-      Feature f = fi.next();
-      Number xValue = (Number)f.getAttribute(xAttr);
-      Number yValue = (Number)f.getAttribute(yAttr);
-      xySeries.add(xValue, yValue);
-      // Mapping between FID und data index in series
-      mapping.setMapping(f.getID(), seriesKey, i);
-      LOGGER.debug(f.getID() + " --> "+i);
-    }
-    return dataset;
-  }
-  
-  /**
-   * Creates a {@link JFreeChart} which shows a point for each feature and
-   * a the appropriate regression line.
-   * @param fc      a {@link FeatureCollection}
-   * @param title   title for the chart (also used as key for the {@link XYSeries})
-   * @param xAttr   feature attribute used for the X-value
-   * @param yAttr   feature attribute used for the Y-value
-   * @param regressionLine indicates whether the regression line is shown
-   */
-  public static JFreeChart createRegressionChart(FeatureCollection fc, String title, String xAttr, String yAttr, boolean regressionLine) {
-    XYSeriesCollection  dataset = createXYDataset(fc, title, xAttr, yAttr);
-    return createRegressionChart(dataset, title, xAttr, yAttr, regressionLine);
-  }
-  
-  /**
-   * Creates a {@link JFreeChart} which shows a point for each data iten and
-   * a the appropriate regression line.
-   * @param dataset        the data
-   * @param title          title for the chart
-   * @param xAxisTitle     title for the X-Axis
-   * @param yAxisTitle     title for the Y-Axis
-   * @param regressionLine indicates whether the regression line is shown
-   */
-  public static JFreeChart createRegressionChart(XYDataset dataset, String title, String xAxisTitle, String yAxisTitle, boolean regressionLine) {
-    if ( regressionLine && !(dataset instanceof XYSeriesCollection) )
-      throw new UnsupportedOperationException("Regression line can only be created for XYSeriesCollection!");
-    
-    NumberAxis xAxis   = new NumberAxis(xAxisTitle);
-    xAxis.setAutoRangeIncludesZero(false);
-    NumberAxis yAxis   = new NumberAxis(yAxisTitle);
-    yAxis.setAutoRangeIncludesZero(false);
-
-    XYPlot             plot             = new XYPlot(dataset, xAxis, yAxis, null);
-    XYToolTipGenerator toolTipGenerator = new StandardXYToolTipGenerator();
-    XYURLGenerator     urlGenerator     = new StandardXYURLGenerator();
-    XYItemRenderer     renderer         = new SelectionXYLineAndShapeRenderer(false, true) {
-      @Override
-      public FeatureSeriesDatasetSelectionModel createSelectionModel(XYDataset dataset) {
-        return new FeatureSeriesDatasetSelectionModel(dataset);
-      }
-    };
-    
-    renderer.setBaseToolTipGenerator(toolTipGenerator);
-    renderer.setURLGenerator(urlGenerator);
-    plot.setRenderer(renderer);
-    plot.setOrientation(PlotOrientation.VERTICAL);
-    
-    // Regression line
-    if ( regressionLine ) {
-      // create sample data for curve (plot function directly is not yet available)
-      XYDataset regressionData = createRegressionLineDataset((XYSeriesCollection)dataset,0,title+" (RegressionLine)",2);
-      addRegressionLineToPlot(plot, regressionData, Color.blue);
-    }
-    JFreeChart chart = new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT, plot, true);
-
-    return chart; //ChartFactory.createScatterPlot(title, xAttr, yAttr, dataset, PlotOrientation.HORIZONTAL, true, true, true);
-  }
-
-  /**
-   * Creates sample data for a regression line of an {@link XYDataset}.
-   * @param dataset    data the regression line is created for
-   * @param series     series of {@code dataset} the regression line is created for
-   * @param seriesKey  the key for the created dataset
-   * @param sampleCnt  count of created samples
-   */
-  public static XYDataset createRegressionLineDataset(XYSeriesCollection dataset, int series, Comparable seriesKey, int sampleCount) {
-    double minX = dataset.getSeries(0).getMinX();
-    double maxX = dataset.getSeries(0).getMaxX();
-    return createRegressionLineDataset(dataset,series,seriesKey,minX,maxX,sampleCount);
-  }
-
-  /**
-   * Creates sample data for a regression line of an {@link XYDataset}.
-   * @param dataset    data the regression line is created for
-   * @param series     series of {@code dataset} the regression line is created for
-   * @param seriesKey  the key for the created dataset
-   * @param startX     the first value the sample data is created for
-   * @param endX       the last value the sample data is created for
-   * @param sampleCnt  count of created samples
-   */
-  public static XYDataset createRegressionLineDataset(XYDataset dataset, int series, Comparable seriesKey, double startX, double endX, int sampleCount) {
-    double[]   coefficients = Regression.getOLSRegression(dataset, series);
-    Function2D curve        = new LineFunction2D(coefficients[0], coefficients[1]);
-    return DatasetUtilities.sampleFunction2D(curve, startX, endX, 2, seriesKey);
-  }
-
-  /**
-   * Adds a line plot for regression data to a plot. 
-   * @param plot           the plot the line is added to (at the end)
-   * @param regressionData the regression data
-   * @param lineColor      the color for the regression line
-   */
-  public static void addRegressionLineToPlot(XYPlot plot, XYDataset regressionData, Color lineColor) {
-    int datasetCount = plot.getDatasetCount();
-    // set the regression data
-    plot.setDataset(datasetCount, regressionData);
-    // create and set the renderer for the regression line
-    XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(true,false);
-    renderer.setSeriesPaint(0, Color.blue);
-    plot.setRenderer(datasetCount, renderer);
-  }
-
-  /**
-   * @return all {@link DatasetSelectionModel DatasetSelectionModels} that can be reached via the renderers of this chart. 
-   */
-  public static List<FeatureDatasetSelectionModel<?>> getFeatureDatasetSelectionModelFor(JFreeChart chart) {
-	ArrayList<FeatureDatasetSelectionModel<?>> renderers = new ArrayList<FeatureDatasetSelectionModel<?>>();
-	
-	Plot plot = chart.getPlot();
-	
-	if (plot instanceof XYPlot) {
-		XYPlot xyplot = (XYPlot)plot;
-
-		for (int i = 0; i < xyplot.getRendererCount(); i++) {
-			XYItemRenderer renderer = xyplot.getRenderer(i);
-			if (renderer instanceof DatasetSelectionModelProvider &&
-			    ((DatasetSelectionModelProvider)renderer).getSelectionModel() instanceof FeatureDatasetSelectionModel){
-				renderers.add( (FeatureDatasetSelectionModel)((DatasetSelectionModelProvider)renderer).getSelectionModel());
-			}
-		}
-	}
-	
-	// TODO Other types of Charts have the renderers hidden somewhere else.
-	
-	return renderers;
-  }
-  
-
-
-//###################
-//  BISHER NUR WILDE TESTS
-//###################
-//  /**
-//   * Converts a Excel file to CVS format.
-//   * @param xlsInput  stream to Excel source
-//   * @param sheetName name of the sheet in the Excel source (if {@code null} the
-//   *                  first sheet is used)
-//   * @param headRow   indicates whether the first row contains the column names
-//   * @param csvHeader indicates whether the column names are also taken to the CVS (note:
-//   *                  if {@code true} and {@code headRow = false} dummy column
-//   *                  names "A", "B", ... are generates in CVS!)
-//   * @param delimChr  character takes as delimiter in CSV  
-//   * @param strEncChr character String values are encapsulated with (if {@code null}, Strings
-//   *                  are not encapsulated)                  
-//   */
-//  public static InputStream createCSVFromXLS(InputStream xlsInput, String sheetName, boolean headRow, boolean csvHeader, String delimChr, String strEncChar) throws IOException {
-//    PipedOutputStream csvOutput = new PipedOutputStream();
-//   
-//    // read XLS and create a CSV
-//    HSSFWorkbook wb    = new HSSFWorkbook( new POIFSFileSystem(xlsInput) );
-//    HSSFSheet    sheet = ( sheetName != null ) ? wb.getSheet(sheetName) : wb.getSheetAt(0);
-//    
-//    int firstRow = sheet.getFirstRowNum();
-//    int lastRow  = sheet.getLastRowNum();
-////    int rowCount = sheet.getPhysicalNumberOfRows();
-//    for (int y=firstRow; y <= lastRow; y++) {
-//      HSSFRow row = sheet.getRow(y);
-//      int firstCol = row.getFirstCellNum();
-//      int lastCol  = row.getLastCellNum();
-//      for (int x=firstCol; x <= lastCol; x++) {
-//        HSSFCell cell = row.getCell(x);
-////        String csvValue = convertCellValueToString(cell,???);
-//      }
-//    }
-//   
-//    return new PipedInputStream(csvOutput);
-//  }
-//  
-//  public static String convertCellValueToString(HSSFCell cell, HSSFFormulaEvaluator formulaEvaluator) {
-//    String strValue = "";
-//    switch( cell.getCellType() ) {
-//      case HSSFCell.CELL_TYPE_BOOLEAN: strValue = ""+cell.getBooleanCellValue();
-//                                       break;
-//      case HSSFCell.CELL_TYPE_NUMERIC: strValue = ""+cell.getNumericCellValue();
-//                                       break;
-//      case HSSFCell.CELL_TYPE_FORMULA: strValue = ""+cell.getNumericCellValue();
-//    }
-//    return strValue;
-//    
-//  }
-//
-//  /**
-//   * Creates a Dataset from Excel file.
-//   * @param xlsInput  stream to Excel source
-//   * @param sheetName name of the sheet in the Excel source (if {@code null} the
-//   *                  first sheet is used)
-//   */
-//  public static CategoryDataset createDatasetFromXLS(InputStream xlsInput, String sheetName) throws IOException {
-//    PipedOutputStream csvOutput = new PipedOutputStream();
-//    InputStreamReader csvInput  = new InputStreamReader( new PipedInputStream(csvOutput) ); 
-//    
-//
-////    return new CSV(';','"').readCategoryDataset(csvInput);
-//
-//    HSSFWorkbook wb = new HSSFWorkbook(new POIFSFileSystem(xlsInput));
-//    ExcelExtractor extractor = new ExcelExtractor(wb);
-//    
-//    extractor.setFormulasNotResults(false);
-//    extractor.setIncludeSheetNames(false);
-//    String text = extractor.getText();
-//    System.out.println(text);
-//    return null;
-//  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.jfree;
+
+import java.awt.Color;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
+
+import org.apache.log4j.Logger;
+import org.geotools.feature.AttributeType;
+import org.geotools.feature.Feature;
+import org.geotools.feature.FeatureCollection;
+import org.geotools.feature.FeatureIterator;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.axis.NumberAxis;
+import org.jfree.chart.event.PlotChangeEvent;
+import org.jfree.chart.event.PlotChangeListener;
+import org.jfree.chart.event.RendererChangeEvent;
+import org.jfree.chart.event.RendererChangeListener;
+import org.jfree.chart.labels.StandardXYToolTipGenerator;
+import org.jfree.chart.labels.XYToolTipGenerator;
+import org.jfree.chart.plot.Plot;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.chart.renderer.AbstractRenderer;
+import org.jfree.chart.renderer.category.AreaRenderer;
+import org.jfree.chart.renderer.category.BarRenderer;
+import org.jfree.chart.renderer.category.CategoryItemRenderer;
+import org.jfree.chart.renderer.category.CategoryStepRenderer;
+import org.jfree.chart.renderer.category.LineAndShapeRenderer;
+import org.jfree.chart.renderer.category.StackedAreaRenderer;
+import org.jfree.chart.renderer.category.StackedBarRenderer;
+import org.jfree.chart.renderer.xy.StackedXYAreaRenderer2;
+import org.jfree.chart.renderer.xy.StackedXYBarRenderer;
+import org.jfree.chart.renderer.xy.XYAreaRenderer;
+import org.jfree.chart.renderer.xy.XYBarRenderer;
+import org.jfree.chart.renderer.xy.XYItemRenderer;
+import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
+import org.jfree.chart.renderer.xy.XYStepAreaRenderer;
+import org.jfree.chart.renderer.xy.XYStepRenderer;
+import org.jfree.chart.title.LegendTitle;
+import org.jfree.chart.title.Title;
+import org.jfree.chart.urls.StandardXYURLGenerator;
+import org.jfree.chart.urls.XYURLGenerator;
+import org.jfree.data.function.Function2D;
+import org.jfree.data.function.LineFunction2D;
+import org.jfree.data.general.DatasetUtilities;
+import org.jfree.data.statistics.Regression;
+import org.jfree.data.xy.XYDataset;
+import org.jfree.data.xy.XYSeries;
+import org.jfree.data.xy.XYSeriesCollection;
+
+import schmitzm.jfree.chart.renderer.SelectionXYLineAndShapeRenderer;
+import schmitzm.jfree.chart.selection.DatasetSelectionModel;
+import schmitzm.jfree.chart.selection.DatasetSelectionModelProvider;
+import schmitzm.jfree.chart.style.BasicChartStyle;
+import schmitzm.jfree.chart.style.ChartStyle;
+import schmitzm.jfree.chart.style.ChartStyleXMLFactory;
+import schmitzm.jfree.chart.style.ChartType;
+import schmitzm.jfree.feature.Feature2SeriesDatasetMapping;
+import schmitzm.jfree.feature.FeatureDatasetMetaData;
+import schmitzm.jfree.feature.FeatureDatasetSelectionModel;
+import schmitzm.jfree.feature.FeatureSeriesDatasetSelectionModel;
+import schmitzm.lang.LangUtil;
+import schmitzm.lang.ResourceProvider;
+
+/**
+ * In dieser Klasse sind Hilfsmethoden fuer JFreeChart hinterlegt.
+ * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class JFreeChartUtil {
+  private static Logger LOGGER = Logger.getLogger(JFreeChartUtil.class.getName());
+  
+  /** {@link ResourceProvider}, der die Lokalisation fuer GUI-Komponenten
+   *  zur Verfuegung stellt. Diese sind in properties-Datein unter
+   *  {@code schmitzm.jfree.resource.locales.JFreeResourceBundle_XXX.properties}
+   *  hinterlegt. */
+  public static ResourceProvider RESOURCE = new ResourceProvider( LangUtil.extendPackagePath(JFreeChartUtil.class,"resource.locales.JFreeResourceBundle"), Locale.ENGLISH );
+
+	/**
+	 * Convenience method to access the {@link ResourceProvider}.
+	*/
+	public static String R(String key, Object... values) {
+		return RESOURCE.getString(key, values);
+	}
+
+  /** Instance of {@link ChartStyleXMLFactory}. */
+  public static final ChartStyleXMLFactory<ChartStyle> CHART_STYLE_FACTORY = new ChartStyleXMLFactory<ChartStyle>();
+
+  /**
+   * Sets all chart legends (in)visible.
+   * @param chart   a chart to apply
+   * @param visible indicates the visible property
+   */
+  public static void setLegendVisible(JFreeChart chart, boolean visible) {
+    for (Object title : chart.getSubtitles())
+      if ( title instanceof LegendTitle )
+        ((Title)title).setVisible(visible);
+  }
+  
+  /**
+   * Fires a change event to all {@link PlotChangeListener} connected
+   * to the plot. 
+   * @param plot a plot
+   */
+  public static void fireChangeEvent(Plot plot) {
+    plot.notifyListeners( new PlotChangeEvent(plot) );
+  }
+  
+  /**
+   * Fires a change event to all {@link RendererChangeListener} connected
+   * to the renderer. 
+   * @param renderer a renderer
+   */
+  public static void fireChangeEvent(AbstractRenderer renderer) {
+    renderer.notifyListeners( new RendererChangeEvent(renderer) );
+  }
+
+  /**
+   * Creates a {@link XYItemRenderer} for the given stepped and stacked
+   * properties.
+   * @param type    chart type
+   * @param stepped stepped property
+   * @param stacked stacked property
+   */
+  public static XYItemRenderer createXYRenderer(BasicChartStyle style) {
+    return createXYRenderer(
+        style.getType(),
+        style.isStepped(),
+        style.isStacked()
+    );
+  }
+  
+  /**
+   * Creates a {@link XYItemRenderer} for the given stepped and stacked
+   * properties.
+   * @param type    chart type
+   * @param stepped stepped property
+   * @param stacked stacked property
+   */
+  public static XYItemRenderer createXYRenderer(ChartType type, boolean stepped, boolean stacked) {
+    switch ( type ) {
+      case LINE: // "stacked" is not available for line charts
+                 if ( stacked )
+                   LOGGER.warn("Stacked property can not be applied to line charts. Property ignored!");
+                 // Create renderer according to "stepped"
+                 if ( stepped )
+                   return new XYStepRenderer();
+                 // normal line renderer
+                 return new XYLineAndShapeRenderer(true, false);
+      case AREA: // Apply stacked
+                 if ( stacked ) {
+                   // "stacked" and "stepped" can not be applied the same time
+                   if ( stepped )
+                     LOGGER.warn("A stacked area chart can not be stepped the same time (use a stacked bar chart instead). Stepped propery ignored!");
+                   // Stacked area renderer
+                   return new StackedXYAreaRenderer2();
+                 }
+                 // Stepped area renderer
+                 if ( stepped )
+                   return new XYStepAreaRenderer(XYStepAreaRenderer.AREA);
+                 // Neither stepped nor stepped
+                 return new XYAreaRenderer(XYAreaRenderer.AREA);
+      case BAR: // bar charts are automatically stepped,
+                // so only "stacked" is applied
+                if ( stacked )
+                  return new StackedXYBarRenderer();
+                // Normal bar renderer
+                return new XYBarRenderer();
+    }
+    throw new UnsupportedOperationException("XYItemRenderer could not be created for chart type: "+type); 
+  }
+
+  
+  /**
+   * Creates a {@link CategoryItemRenderer} for the given stepped and stacked
+   * properties.
+   * @param type    chart type
+   * @param stepped stepped property
+   * @param stacked stacked property
+   */
+  public static CategoryItemRenderer createCategoryRenderer(BasicChartStyle style) {
+    return createCategoryRenderer(
+        style.getType(),
+        style.isStepped(),
+        style.isStacked()
+    );
+  }
+  
+  /**
+   * Creates a {@link CategoryItemRenderer} for the given stepped and stacked
+   * properties.
+   * @param type    chart type
+   * @param stepped stepped property
+   * @param stacked stacked property
+   */
+  public static CategoryItemRenderer createCategoryRenderer(ChartType type, boolean stepped, boolean stacked) {
+    switch ( type ) {
+      case LINE: // "stacked" is not available for line charts
+                 if ( stacked )
+                   LOGGER.warn("Stacked property can not be applied to line charts. Property ignored!");
+                 // Create renderer according to "stepped"
+                 if ( stepped )
+                   return new CategoryStepRenderer();
+                 // normal line renderer
+                 return new LineAndShapeRenderer(true, false);
+      case AREA: // category area chart is automatically stepped,
+                 // so only "stacked" is applied
+                 if ( stacked )
+                   return new StackedAreaRenderer(false);
+                 // Normal area renderer
+                 return new AreaRenderer();
+      case BAR: // bar charts are automatically stepped,
+                // so only "stacked" is applied
+                if ( stacked )
+                  return new StackedBarRenderer(false);
+                // Normal bar renderer
+                return new BarRenderer();
+    }
+    throw new UnsupportedOperationException("CategoryItemRenderer could not be created for chart type: "+type); 
+  }
+
+  /**
+   * Creates a {@link XYDataset} for 2 attributes of a {@link FeatureCollection}.
+   * @param fc    a {@link FeatureCollection}
+   * @param seriesKey   a (unique) key for the {@link XYSeries} in the dataset
+   * @param xAttr feature attribute used for the X-value
+   * @param yAttr feature attribute used for the Y-value
+   */
+  public static XYSeriesCollection createXYDataset(FeatureCollection fc, String seriesKey, String xAttr, String yAttr) {
+    // check data types of X- and Y-column
+    AttributeType xType = fc.getSchema().getAttributeType(xAttr);
+    if ( xType == null )
+      throw new UnsupportedOperationException("Unknown attribute: "+xAttr);
+    AttributeType yType = fc.getSchema().getAttributeType(yAttr);
+    if ( yType == null )
+      throw new UnsupportedOperationException("Unknown attribute: "+yAttr);
+    if ( !Number.class.isAssignableFrom(xType.getBinding()) )
+      throw new UnsupportedOperationException("Attribute must be numeric: "+xAttr);
+    if ( !Number.class.isAssignableFrom(yType.getBinding()) )
+      throw new UnsupportedOperationException("Attribute must be numeric: "+yAttr);
+    
+    
+    XYSeriesCollection           dataset   = new XYSeriesCollection();
+    Feature2SeriesDatasetMapping mapping   = new Feature2SeriesDatasetMapping(fc,dataset);
+    FeatureIterator              fi        = fc.features();
+    XYSeries                     xySeries  = new XYSeries(seriesKey,false,true);
+    dataset.addSeries(xySeries);
+    dataset.setGroup( new FeatureDatasetMetaData(mapping) );
+    for (int i=0; fi.hasNext(); i++) {
+      Feature f = fi.next();
+      Number xValue = (Number)f.getAttribute(xAttr);
+      Number yValue = (Number)f.getAttribute(yAttr);
+      xySeries.add(xValue, yValue);
+      // Mapping between FID und data index in series
+      mapping.setMapping(f.getID(), seriesKey, i);
+      LOGGER.debug(f.getID() + " --> "+i);
+    }
+    return dataset;
+  }
+  
+  /**
+   * Creates a {@link JFreeChart} which shows a point for each feature and
+   * a the appropriate regression line.
+   * @param fc      a {@link FeatureCollection}
+   * @param title   title for the chart (also used as key for the {@link XYSeries})
+   * @param xAttr   feature attribute used for the X-value
+   * @param yAttr   feature attribute used for the Y-value
+   * @param regressionLine indicates whether the regression line is shown
+   */
+  public static JFreeChart createRegressionChart(FeatureCollection fc, String title, String xAttr, String yAttr, boolean regressionLine) {
+    XYSeriesCollection  dataset = createXYDataset(fc, title, xAttr, yAttr);
+    return createRegressionChart(dataset, title, xAttr, yAttr, regressionLine);
+  }
+  
+  /**
+   * Creates a {@link JFreeChart} which shows a point for each data iten and
+   * a the appropriate regression line.
+   * @param dataset        the data
+   * @param title          title for the chart
+   * @param xAxisTitle     title for the X-Axis
+   * @param yAxisTitle     title for the Y-Axis
+   * @param regressionLine indicates whether the regression line is shown
+   */
+  public static JFreeChart createRegressionChart(XYDataset dataset, String title, String xAxisTitle, String yAxisTitle, boolean regressionLine) {
+    if ( regressionLine && !(dataset instanceof XYSeriesCollection) )
+      throw new UnsupportedOperationException("Regression line can only be created for XYSeriesCollection!");
+    
+    NumberAxis xAxis   = new NumberAxis(xAxisTitle);
+    xAxis.setAutoRangeIncludesZero(false);
+    NumberAxis yAxis   = new NumberAxis(yAxisTitle);
+    yAxis.setAutoRangeIncludesZero(false);
+
+    XYPlot             plot             = new XYPlot(dataset, xAxis, yAxis, null);
+    XYToolTipGenerator toolTipGenerator = new StandardXYToolTipGenerator();
+    XYURLGenerator     urlGenerator     = new StandardXYURLGenerator();
+    XYItemRenderer     renderer         = new SelectionXYLineAndShapeRenderer(false, true) {
+      @Override
+      public FeatureSeriesDatasetSelectionModel createSelectionModel(XYDataset dataset) {
+        return new FeatureSeriesDatasetSelectionModel(dataset);
+      }
+    };
+    
+    renderer.setBaseToolTipGenerator(toolTipGenerator);
+    renderer.setURLGenerator(urlGenerator);
+    plot.setRenderer(renderer);
+    plot.setOrientation(PlotOrientation.VERTICAL);
+    
+    // Regression line
+    if ( regressionLine ) {
+      // create sample data for curve (plot function directly is not yet available)
+      XYDataset regressionData = createRegressionLineDataset((XYSeriesCollection)dataset,0,title+" (RegressionLine)",2);
+      addRegressionLineToPlot(plot, regressionData, Color.blue);
+    }
+    JFreeChart chart = new JFreeChart(title, JFreeChart.DEFAULT_TITLE_FONT, plot, true);
+
+    return chart; //ChartFactory.createScatterPlot(title, xAttr, yAttr, dataset, PlotOrientation.HORIZONTAL, true, true, true);
+  }
+
+  /**
+   * Creates sample data for a regression line of an {@link XYDataset}.
+   * @param dataset    data the regression line is created for
+   * @param series     series of {@code dataset} the regression line is created for
+   * @param seriesKey  the key for the created dataset
+   * @param sampleCnt  count of created samples
+   */
+  public static XYDataset createRegressionLineDataset(XYSeriesCollection dataset, int series, Comparable seriesKey, int sampleCount) {
+    double minX = dataset.getSeries(0).getMinX();
+    double maxX = dataset.getSeries(0).getMaxX();
+    return createRegressionLineDataset(dataset,series,seriesKey,minX,maxX,sampleCount);
+  }
+
+  /**
+   * Creates sample data for a regression line of an {@link XYDataset}.
+   * @param dataset    data the regression line is created for
+   * @param series     series of {@code dataset} the regression line is created for
+   * @param seriesKey  the key for the created dataset
+   * @param startX     the first value the sample data is created for
+   * @param endX       the last value the sample data is created for
+   * @param sampleCnt  count of created samples
+   */
+  public static XYDataset createRegressionLineDataset(XYDataset dataset, int series, Comparable seriesKey, double startX, double endX, int sampleCount) {
+    double[]   coefficients = Regression.getOLSRegression(dataset, series);
+    Function2D curve        = new LineFunction2D(coefficients[0], coefficients[1]);
+    return DatasetUtilities.sampleFunction2D(curve, startX, endX, 2, seriesKey);
+  }
+
+  /**
+   * Adds a line plot for regression data to a plot. 
+   * @param plot           the plot the line is added to (at the end)
+   * @param regressionData the regression data
+   * @param lineColor      the color for the regression line
+   */
+  public static void addRegressionLineToPlot(XYPlot plot, XYDataset regressionData, Color lineColor) {
+    int datasetCount = plot.getDatasetCount();
+    // set the regression data
+    plot.setDataset(datasetCount, regressionData);
+    // create and set the renderer for the regression line
+    XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer(true,false);
+    renderer.setSeriesPaint(0, Color.blue);
+    plot.setRenderer(datasetCount, renderer);
+  }
+
+  /**
+   * @return all {@link DatasetSelectionModel DatasetSelectionModels} that can be reached via the renderers of this chart. 
+   */
+  public static List<FeatureDatasetSelectionModel<?>> getFeatureDatasetSelectionModelFor(JFreeChart chart) {
+	ArrayList<FeatureDatasetSelectionModel<?>> renderers = new ArrayList<FeatureDatasetSelectionModel<?>>();
+	
+	Plot plot = chart.getPlot();
+	
+	if (plot instanceof XYPlot) {
+		XYPlot xyplot = (XYPlot)plot;
+
+		for (int i = 0; i < xyplot.getRendererCount(); i++) {
+			XYItemRenderer renderer = xyplot.getRenderer(i);
+			if (renderer instanceof DatasetSelectionModelProvider &&
+			    ((DatasetSelectionModelProvider)renderer).getSelectionModel() instanceof FeatureDatasetSelectionModel){
+				renderers.add( (FeatureDatasetSelectionModel)((DatasetSelectionModelProvider)renderer).getSelectionModel());
+			}
+		}
+	}
+	
+	// TODO Other types of Charts have the renderers hidden somewhere else.
+	
+	return renderers;
+  }
+  
+
+
+//###################
+//  BISHER NUR WILDE TESTS
+//###################
+//  /**
+//   * Converts a Excel file to CVS format.
+//   * @param xlsInput  stream to Excel source
+//   * @param sheetName name of the sheet in the Excel source (if {@code null} the
+//   *                  first sheet is used)
+//   * @param headRow   indicates whether the first row contains the column names
+//   * @param csvHeader indicates whether the column names are also taken to the CVS (note:
+//   *                  if {@code true} and {@code headRow = false} dummy column
+//   *                  names "A", "B", ... are generates in CVS!)
+//   * @param delimChr  character takes as delimiter in CSV  
+//   * @param strEncChr character String values are encapsulated with (if {@code null}, Strings
+//   *                  are not encapsulated)                  
+//   */
+//  public static InputStream createCSVFromXLS(InputStream xlsInput, String sheetName, boolean headRow, boolean csvHeader, String delimChr, String strEncChar) throws IOException {
+//    PipedOutputStream csvOutput = new PipedOutputStream();
+//   
+//    // read XLS and create a CSV
+//    HSSFWorkbook wb    = new HSSFWorkbook( new POIFSFileSystem(xlsInput) );
+//    HSSFSheet    sheet = ( sheetName != null ) ? wb.getSheet(sheetName) : wb.getSheetAt(0);
+//    
+//    int firstRow = sheet.getFirstRowNum();
+//    int lastRow  = sheet.getLastRowNum();
+////    int rowCount = sheet.getPhysicalNumberOfRows();
+//    for (int y=firstRow; y <= lastRow; y++) {
+//      HSSFRow row = sheet.getRow(y);
+//      int firstCol = row.getFirstCellNum();
+//      int lastCol  = row.getLastCellNum();
+//      for (int x=firstCol; x <= lastCol; x++) {
+//        HSSFCell cell = row.getCell(x);
+////        String csvValue = convertCellValueToString(cell,???);
+//      }
+//    }
+//   
+//    return new PipedInputStream(csvOutput);
+//  }
+//  
+//  public static String convertCellValueToString(HSSFCell cell, HSSFFormulaEvaluator formulaEvaluator) {
+//    String strValue = "";
+//    switch( cell.getCellType() ) {
+//      case HSSFCell.CELL_TYPE_BOOLEAN: strValue = ""+cell.getBooleanCellValue();
+//                                       break;
+//      case HSSFCell.CELL_TYPE_NUMERIC: strValue = ""+cell.getNumericCellValue();
+//                                       break;
+//      case HSSFCell.CELL_TYPE_FORMULA: strValue = ""+cell.getNumericCellValue();
+//    }
+//    return strValue;
+//    
+//  }
+//
+//  /**
+//   * Creates a Dataset from Excel file.
+//   * @param xlsInput  stream to Excel source
+//   * @param sheetName name of the sheet in the Excel source (if {@code null} the
+//   *                  first sheet is used)
+//   */
+//  public static CategoryDataset createDatasetFromXLS(InputStream xlsInput, String sheetName) throws IOException {
+//    PipedOutputStream csvOutput = new PipedOutputStream();
+//    InputStreamReader csvInput  = new InputStreamReader( new PipedInputStream(csvOutput) ); 
+//    
+//
+////    return new CSV(';','"').readCategoryDataset(csvInput);
+//
+//    HSSFWorkbook wb = new HSSFWorkbook(new POIFSFileSystem(xlsInput));
+//    ExcelExtractor extractor = new ExcelExtractor(wb);
+//    
+//    extractor.setFormulasNotResults(false);
+//    extractor.setIncludeSheetNames(false);
+//    String text = extractor.getText();
+//    System.out.println(text);
+//    return null;
+//  }
+}

Modified: trunk/src/schmitzm/jfree/chart/ChartMouseSelectionTracker.java
===================================================================
--- trunk/src/schmitzm/jfree/chart/ChartMouseSelectionTracker.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/chart/ChartMouseSelectionTracker.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,76 +1,95 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.jfree.chart;
-
-import java.awt.geom.Rectangle2D;
-import java.util.HashSet;
-import java.util.Set;
-
-import org.jfree.chart.ChartPanel;
-import org.jfree.chart.entity.ChartEntity;
-import org.jfree.chart.entity.EntityCollection;
-import org.jfree.chart.entity.XYItemEntity;
-
-import schmitzm.geotools.gui.MouseSelectionTracker;
-
-/**
- * This tracker listens to mouse window selections on a {@link ChartPanel}.
- * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
- */
-public abstract class ChartMouseSelectionTracker extends MouseSelectionTracker {
-  /** Holds the panel connected to this listener. */
-  protected ChartPanel chartPanel = null;
-  
-  /**
-   * Creates a new listener.
-   * @param panel the chart panel connected to the listener (used to
-   *              determine the {@link EntityCollection})
-   */
-  public ChartMouseSelectionTracker(ChartPanel panel) {
-    super();
-    this.chartPanel = panel;
-  }
-  
-  /**
-   * Reacts on the window selection by determining all {@link XYItemEntity XYItemEntities}
-   * intersected by the selection window.
-   */
-  @Override
-  protected void selectionPerformed(int ox, int oy, int px, int py) {
-    // Create rectangle for selection window
-    Rectangle2D selectedArea = new Rectangle2D.Double(
-                                     Math.min(ox,px),
-                                     Math.min(oy,py),
-                                     Math.abs(ox-px),
-                                     Math.abs(oy-py) );
-
-    // Check every chart data points if the selection area
-    // contains it   
-    HashSet<XYItemEntity> selectedEntities = new HashSet<XYItemEntity>();
-    for( Object entityObj : chartPanel.getChartRenderingInfo().getEntityCollection().getEntities() ) {
-      ChartEntity entity = (ChartEntity)entityObj;
-      // ignore all non-data entities
-      if ( !(entity instanceof XYItemEntity) )
-        continue;
-      if ( entity.getArea().intersects(selectedArea) )
-        selectedEntities.add( (XYItemEntity)entity );
-    }
-    selectionPerformed(selectedArea, selectedEntities);
-  }
-  
-  /**
-   * Called after {@link #selectionPerformed(int, int, int, int)} to inform
-   * the listeners about the selected items.
-   * @param rect             the selection range
-   * @param selectedEntities the selected {@link XYItemEntity XYItemEntities}
-   */
-  protected abstract void selectionPerformed(Rectangle2D rect, Set<XYItemEntity> selectedEntities);
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.jfree.chart;
+
+import java.awt.geom.Rectangle2D;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.jfree.chart.ChartPanel;
+import org.jfree.chart.entity.ChartEntity;
+import org.jfree.chart.entity.EntityCollection;
+import org.jfree.chart.entity.XYItemEntity;
+
+import schmitzm.geotools.gui.MouseSelectionTracker;
+
+/**
+ * This tracker listens to mouse window selections on a {@link ChartPanel}.
+ * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
+ */
+public abstract class ChartMouseSelectionTracker extends MouseSelectionTracker {
+  /** Holds the panel connected to this listener. */
+  protected ChartPanel chartPanel = null;
+  
+  /**
+   * Creates a new listener.
+   * @param panel the chart panel connected to the listener (used to
+   *              determine the {@link EntityCollection})
+   */
+  public ChartMouseSelectionTracker(ChartPanel panel) {
+    super();
+    this.chartPanel = panel;
+  }
+  
+  /**
+   * Reacts on the window selection by determining all {@link XYItemEntity XYItemEntities}
+   * intersected by the selection window.
+   */
+  @Override
+  protected void selectionPerformed(int ox, int oy, int px, int py) {
+    // Create rectangle for selection window
+    Rectangle2D selectedArea = new Rectangle2D.Double(
+                                     Math.min(ox,px),
+                                     Math.min(oy,py),
+                                     Math.abs(ox-px),
+                                     Math.abs(oy-py) );
+
+    // Check every chart data points if the selection area
+    // contains it   
+    HashSet<XYItemEntity> selectedEntities = new HashSet<XYItemEntity>();
+    for( Object entityObj : chartPanel.getChartRenderingInfo().getEntityCollection().getEntities() ) {
+      ChartEntity entity = (ChartEntity)entityObj;
+      // ignore all non-data entities
+      if ( !(entity instanceof XYItemEntity) )
+        continue;
+      if ( entity.getArea().intersects(selectedArea) )
+        selectedEntities.add( (XYItemEntity)entity );
+    }
+    selectionPerformed(selectedArea, selectedEntities);
+  }
+  
+  /**
+   * Called after {@link #selectionPerformed(int, int, int, int)} to inform
+   * the listeners about the selected items.
+   * @param rect             the selection range
+   * @param selectedEntities the selected {@link XYItemEntity XYItemEntities}
+   */
+  protected abstract void selectionPerformed(Rectangle2D rect, Set<XYItemEntity> selectedEntities);
+}

Modified: trunk/src/schmitzm/jfree/chart/SelectableChartPanel.java
===================================================================
--- trunk/src/schmitzm/jfree/chart/SelectableChartPanel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/chart/SelectableChartPanel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,273 +1,292 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.jfree.chart;
-
-import java.awt.event.MouseEvent;
-import java.awt.geom.Rectangle2D;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-
-import org.apache.log4j.Logger;
-import org.jfree.chart.JFreeChart;
-import org.jfree.chart.entity.XYItemEntity;
-import org.jfree.chart.plot.Plot;
-import org.jfree.chart.plot.XYPlot;
-import org.jfree.chart.renderer.xy.XYItemRenderer;
-import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
-import org.jfree.data.general.Dataset;
-import org.jfree.data.xy.XYDataset;
-
-import schmitzm.jfree.chart.selection.DatasetSelectionModel;
-import schmitzm.jfree.chart.selection.DatasetSelectionModelProvider;
-import schmitzm.jfree.chart.selection.SeriesDatasetSelectionModel;
-import schmitzm.lang.LangUtil;
-
-/**
- * This class extends the {@link org.jfree.chart.ChartPanel} with some
- * new  functionalities.
- * <ul>
-*    <li>select chart points and highlight them</li> 
- *   <li>setting window selection mode to ZOOM or SELECT</li>
- * </ul>
- * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
- * @version 1.0
- */
-public class SelectableChartPanel extends org.jfree.chart.ChartPanel {
-  /** Used for log and debug messages. */
-  protected Logger LOGGER = LangUtil.createLogger(this);
-
-  /**
-   * Types of window selection on chart panel. 
-   */
-  public static enum WindowSelectionMode {
-    /** Zoom on window selection (normal behavior of {@link org.jfree.chart.ChartPanel}) */ 
-    ZOOM_IN,
-    /** Select some data points in chart to highlight on window selection. */
-    SELECT,
-  }
-  
-  /** Holds the behavior on window selection (Default: {@link WindowSelectionMode#ZOOM_IN}). */ 
-  protected WindowSelectionMode windowSelectionMode = WindowSelectionMode.ZOOM_IN;
-  
-  /** Listens to mouse window selection on the chart. */
-  protected ChartMouseSelectionTracker selectionTracker = null;
-  
-  /**
-   * Creates a new chart panel.
-   */
-  public SelectableChartPanel(JFreeChart chart) {
-    super(chart);
-    init();
-  }
-
-  /**
-   * Creates a new chart panel.
-   */
-  public SelectableChartPanel(JFreeChart chart, boolean useBuffer) {
-    super(chart, useBuffer);
-    init();
-  }
-
-  /**
-   * Creates a new chart panel.
-   */
-  public SelectableChartPanel(JFreeChart chart, boolean properties, boolean save, boolean print, boolean zoom, boolean tooltips) {
-    super(chart, properties, save, print, zoom, tooltips);
-    init();
-  }
-
-  /**
-   * Creates a new chart panel.
-   */
-  public SelectableChartPanel(JFreeChart chart, int width, int height, int minimumDrawWidth, int minimumDrawHeight, int maximumDrawWidth,
-                                      int maximumDrawHeight, boolean useBuffer, boolean properties, boolean save, boolean print, boolean zoom, boolean tooltips) {
-    super(chart, width, height, minimumDrawWidth, minimumDrawHeight,
-          maximumDrawWidth, maximumDrawHeight, useBuffer, properties, save,
-          print, zoom, tooltips);
-    init();
-  }
-
-  /**
-   * Called by every constructor to initialize the extensions 
-   * of this panel.
-   */
-  protected void init() {
-    selectionTracker = new ChartMouseSelectionTracker(this) {
-      public void selectionPerformed(Rectangle2D selectedArea, Set<XYItemEntity> selectedEntities) {
-        LOGGER.debug( selectedEntities.size() + " objects selected" );
-        
-        // remember all changed selection models to reset "valueAdjusting"
-        // property at the end
-        Set<DatasetSelectionModel<?>> changedModels = new HashSet<DatasetSelectionModel<?>>();
-        Plot plot = getChart().getPlot();
-        for (Iterator<XYItemEntity> i = selectedEntities.iterator(); i.hasNext(); ) {
-          XYItemEntity             e        = i.next();
-          Dataset                  dataset  = e.getDataset();
-          DatasetSelectionModel<?> selModel = null;
-          if ( plot instanceof XYPlot ) {
-           XYItemRenderer renderer = ((XYPlot)plot).getRendererForDataset((XYDataset)dataset);
-           if ( renderer instanceof DatasetSelectionModelProvider )
-             selModel = ((DatasetSelectionModelProvider<?>)renderer).getSelectionModel();
-          }
-
-          // set "valueAdjusting" property for selection model and remember the
-          // model to reset the property at the end
-          if ( selModel != null ) {
-            selModel.setValueIsAdjusting(true);
-            changedModels.add(selModel);
-          }
-          // perform the selection change
-          if ( selModel instanceof SeriesDatasetSelectionModel ) {
-            int series           = e.getSeriesIndex();
-            Comparable seriesKey = e.getDataset().getSeriesKey(series);
-            int item             = e.getItem();
-            ((SeriesDatasetSelectionModel)selModel).changeItemSelection(seriesKey, item);
-          } else {
-            if ( selModel == null )
-              LOGGER.warn("Selection not supported for dataset: "+LangUtil.getSimpleClassName(dataset));
-            else
-              LOGGER.error("Selection not yet implemented for selection model: "+LangUtil.getSimpleClassName(selModel));
-          }
-        }
-        // refresh the visualization
-        refresh();
-        // reset the "valueAdjusting" property to inform listeners
-        // about the selection change
-        for (DatasetSelectionModel<?> selModel : changedModels)
-          selModel.setValueIsAdjusting(false);
-      }
-      
-    };
-    addMouseListener(selectionTracker);
-    setWindowSelectionMode( WindowSelectionMode.ZOOM_IN );
-    
-//    XYPlot                 p = (XYPlot)getChart().getPlot();
-//    XYLineAndShapeRenderer r = (XYLineAndShapeRenderer)p.getRenderer();
-
-//    
-//    XYItemRenderer r2 = new XYLineAndShapeRenderer(r.getBaseLinesVisible(), r.getBaseShapesVisible()) {
-//      public void drawItem(Graphics2D g, XYItemRendererState state,
-//          Rectangle2D dataArea,
-//          PlotRenderingInfo info,
-//          XYPlot plot,
-//          ValueAxis domainAxis,
-//          ValueAxis rangeAxis,
-//          XYDataset dataset,
-//          int series,
-//          int item,
-//          CrosshairState crosshairState,
-//          int pass) {
-//        if ( !selectedIdx.contains(item) )
-//          return;
-//        
-//        super.drawItem(g, state, dataArea, info, plot, domainAxis, rangeAxis, dataset, series, item, crosshairState, pass);
-//      }
-//    };
-//    r.setBasePaint(Color.gray);
-//    r2.setBasePaint(Color.YELLOW);
-//    int datasetCount = p.getDatasetCount();
-//    p.setDataset(datasetCount, p.getDataset());
-//    p.setRenderer(datasetCount, r2);
-//    p.setSeriesRenderingOrder(SeriesRenderingOrder.REVERSE);
-      
-        
-    
-//    addChartMouseListener( new ChartMouseListener() {
-//      @Override
-//      public void chartMouseClicked(ChartMouseEvent e) {
-//        System.err.println("MouseClicked: "+e.getEntity());
-//      }
-//      @Override
-//      public void chartMouseMoved(ChartMouseEvent e) {
-//        System.err.println("MouseMoved: "+e.getEntity());
-//      }
-//    });
-    
-  }
-  
-  /**
-   * Repaints the chart.
-   */
-  public void refresh() {
-    setRefreshBuffer(true);
-    repaint();
-  }
-  
-  /**
-   * After setting a new chart the zoom relevant properties are
-   * reset according to the new chart. After calling the super-method,
-   * this methods resets the properties according to the current
-   * {@link #windowSelectionMode} to keep its functionality remaining.
-   * @see #updateStatesForWindowSelectionMode()
-   */
-  public void setChart(JFreeChart chart) {
-    super.setChart(chart);
-    // zoom relevant properties were reset according to
-    // chart properties!
-    // But we do not want them changed, so reset the states.
-    updateStatesForWindowSelectionMode();
-  }
-  
-  /**
-   * Configures the zoomable properties and {@link #selectionTracker} according
-   * to the current {@link #windowSelectionMode}.
-   */
-  protected void updateStatesForWindowSelectionMode() {
-    // enable/disable the zoom functionality
-    setMouseZoomable( windowSelectionMode == WindowSelectionMode.ZOOM_IN, getFillZoomRectangle() );
-    // enable/disable the selection functionality
-    if ( selectionTracker != null )
-      selectionTracker.setEnabled( windowSelectionMode == WindowSelectionMode.SELECT );
-  }
-  
-  /**
-   * Sets the behavior of the chart panel on window selections via mouse.
-   * @param mode new selection mode
-   */
-  public void setWindowSelectionMode(WindowSelectionMode mode) {
-    this.windowSelectionMode = mode;
-    updateStatesForWindowSelectionMode();
-  }
-
-  /**
-   * Returns the behavior of the chart panel on window selections via mouse.
-   * @param mode new selection mode
-   */
-  public WindowSelectionMode getWindowSelectionMode() {
-    return this.windowSelectionMode; 
-  }
-  
-  /**
-   * Ignores the event if the window selection mode is not
-   * {@link WindowSelectionMode#ZOOM_IN}, to avoid conflicts
-   * between the two listeners.
-   */
-  @Override
-  public void mouseDragged(MouseEvent e) {
-    if ( getWindowSelectionMode() != WindowSelectionMode.ZOOM_IN )
-      return;
-    super.mouseDragged(e);
-  }
-
-  /**
-   * Ignores the event if the window selection mode is not
-   * {@link WindowSelectionMode#ZOOM_IN}, to avoid conflicts
-   * between the two listeners.
-   */
-  @Override
-  public void mouseMoved(MouseEvent e) {
-    if ( getWindowSelectionMode() != WindowSelectionMode.ZOOM_IN )
-      return;
-    super.mouseMoved(e);
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.jfree.chart;
+
+import java.awt.event.MouseEvent;
+import java.awt.geom.Rectangle2D;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.Set;
+
+import org.apache.log4j.Logger;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.entity.XYItemEntity;
+import org.jfree.chart.plot.Plot;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.chart.renderer.xy.XYItemRenderer;
+import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
+import org.jfree.data.general.Dataset;
+import org.jfree.data.xy.XYDataset;
+
+import schmitzm.jfree.chart.selection.DatasetSelectionModel;
+import schmitzm.jfree.chart.selection.DatasetSelectionModelProvider;
+import schmitzm.jfree.chart.selection.SeriesDatasetSelectionModel;
+import schmitzm.lang.LangUtil;
+
+/**
+ * This class extends the {@link org.jfree.chart.ChartPanel} with some
+ * new  functionalities.
+ * <ul>
+*    <li>select chart points and highlight them</li> 
+ *   <li>setting window selection mode to ZOOM or SELECT</li>
+ * </ul>
+ * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
+ * @version 1.0
+ */
+public class SelectableChartPanel extends org.jfree.chart.ChartPanel {
+  /** Used for log and debug messages. */
+  protected Logger LOGGER = LangUtil.createLogger(this);
+
+  /**
+   * Types of window selection on chart panel. 
+   */
+  public static enum WindowSelectionMode {
+    /** Zoom on window selection (normal behavior of {@link org.jfree.chart.ChartPanel}) */ 
+    ZOOM_IN,
+    /** Select some data points in chart to highlight on window selection. */
+    SELECT,
+  }
+  
+  /** Holds the behavior on window selection (Default: {@link WindowSelectionMode#ZOOM_IN}). */ 
+  protected WindowSelectionMode windowSelectionMode = WindowSelectionMode.ZOOM_IN;
+  
+  /** Listens to mouse window selection on the chart. */
+  protected ChartMouseSelectionTracker selectionTracker = null;
+  
+  /**
+   * Creates a new chart panel.
+   */
+  public SelectableChartPanel(JFreeChart chart) {
+    super(chart);
+    init();
+  }
+
+  /**
+   * Creates a new chart panel.
+   */
+  public SelectableChartPanel(JFreeChart chart, boolean useBuffer) {
+    super(chart, useBuffer);
+    init();
+  }
+
+  /**
+   * Creates a new chart panel.
+   */
+  public SelectableChartPanel(JFreeChart chart, boolean properties, boolean save, boolean print, boolean zoom, boolean tooltips) {
+    super(chart, properties, save, print, zoom, tooltips);
+    init();
+  }
+
+  /**
+   * Creates a new chart panel.
+   */
+  public SelectableChartPanel(JFreeChart chart, int width, int height, int minimumDrawWidth, int minimumDrawHeight, int maximumDrawWidth,
+                                      int maximumDrawHeight, boolean useBuffer, boolean properties, boolean save, boolean print, boolean zoom, boolean tooltips) {
+    super(chart, width, height, minimumDrawWidth, minimumDrawHeight,
+          maximumDrawWidth, maximumDrawHeight, useBuffer, properties, save,
+          print, zoom, tooltips);
+    init();
+  }
+
+  /**
+   * Called by every constructor to initialize the extensions 
+   * of this panel.
+   */
+  protected void init() {
+    selectionTracker = new ChartMouseSelectionTracker(this) {
+      public void selectionPerformed(Rectangle2D selectedArea, Set<XYItemEntity> selectedEntities) {
+        LOGGER.debug( selectedEntities.size() + " objects selected" );
+        
+        // remember all changed selection models to reset "valueAdjusting"
+        // property at the end
+        Set<DatasetSelectionModel<?>> changedModels = new HashSet<DatasetSelectionModel<?>>();
+        Plot plot = getChart().getPlot();
+        for (Iterator<XYItemEntity> i = selectedEntities.iterator(); i.hasNext(); ) {
+          XYItemEntity             e        = i.next();
+          Dataset                  dataset  = e.getDataset();
+          DatasetSelectionModel<?> selModel = null;
+          if ( plot instanceof XYPlot ) {
+           XYItemRenderer renderer = ((XYPlot)plot).getRendererForDataset((XYDataset)dataset);
+           if ( renderer instanceof DatasetSelectionModelProvider )
+             selModel = ((DatasetSelectionModelProvider<?>)renderer).getSelectionModel();
+          }
+
+          // set "valueAdjusting" property for selection model and remember the
+          // model to reset the property at the end
+          if ( selModel != null ) {
+            selModel.setValueIsAdjusting(true);
+            changedModels.add(selModel);
+          }
+          // perform the selection change
+          if ( selModel instanceof SeriesDatasetSelectionModel ) {
+            int series           = e.getSeriesIndex();
+            Comparable seriesKey = e.getDataset().getSeriesKey(series);
+            int item             = e.getItem();
+            ((SeriesDatasetSelectionModel)selModel).changeItemSelection(seriesKey, item);
+          } else {
+            if ( selModel == null )
+              LOGGER.warn("Selection not supported for dataset: "+LangUtil.getSimpleClassName(dataset));
+            else
+              LOGGER.error("Selection not yet implemented for selection model: "+LangUtil.getSimpleClassName(selModel));
+          }
+        }
+        // refresh the visualization
+        refresh();
+        // reset the "valueAdjusting" property to inform listeners
+        // about the selection change
+        for (DatasetSelectionModel<?> selModel : changedModels)
+          selModel.setValueIsAdjusting(false);
+      }
+      
+    };
+    addMouseListener(selectionTracker);
+    setWindowSelectionMode( WindowSelectionMode.ZOOM_IN );
+    
+//    XYPlot                 p = (XYPlot)getChart().getPlot();
+//    XYLineAndShapeRenderer r = (XYLineAndShapeRenderer)p.getRenderer();
+
+//    
+//    XYItemRenderer r2 = new XYLineAndShapeRenderer(r.getBaseLinesVisible(), r.getBaseShapesVisible()) {
+//      public void drawItem(Graphics2D g, XYItemRendererState state,
+//          Rectangle2D dataArea,
+//          PlotRenderingInfo info,
+//          XYPlot plot,
+//          ValueAxis domainAxis,
+//          ValueAxis rangeAxis,
+//          XYDataset dataset,
+//          int series,
+//          int item,
+//          CrosshairState crosshairState,
+//          int pass) {
+//        if ( !selectedIdx.contains(item) )
+//          return;
+//        
+//        super.drawItem(g, state, dataArea, info, plot, domainAxis, rangeAxis, dataset, series, item, crosshairState, pass);
+//      }
+//    };
+//    r.setBasePaint(Color.gray);
+//    r2.setBasePaint(Color.YELLOW);
+//    int datasetCount = p.getDatasetCount();
+//    p.setDataset(datasetCount, p.getDataset());
+//    p.setRenderer(datasetCount, r2);
+//    p.setSeriesRenderingOrder(SeriesRenderingOrder.REVERSE);
+      
+        
+    
+//    addChartMouseListener( new ChartMouseListener() {
+//      @Override
+//      public void chartMouseClicked(ChartMouseEvent e) {
+//        System.err.println("MouseClicked: "+e.getEntity());
+//      }
+//      @Override
+//      public void chartMouseMoved(ChartMouseEvent e) {
+//        System.err.println("MouseMoved: "+e.getEntity());
+//      }
+//    });
+    
+  }
+  
+  /**
+   * Repaints the chart.
+   */
+  public void refresh() {
+    setRefreshBuffer(true);
+    repaint();
+  }
+  
+  /**
+   * After setting a new chart the zoom relevant properties are
+   * reset according to the new chart. After calling the super-method,
+   * this methods resets the properties according to the current
+   * {@link #windowSelectionMode} to keep its functionality remaining.
+   * @see #updateStatesForWindowSelectionMode()
+   */
+  public void setChart(JFreeChart chart) {
+    super.setChart(chart);
+    // zoom relevant properties were reset according to
+    // chart properties!
+    // But we do not want them changed, so reset the states.
+    updateStatesForWindowSelectionMode();
+  }
+  
+  /**
+   * Configures the zoomable properties and {@link #selectionTracker} according
+   * to the current {@link #windowSelectionMode}.
+   */
+  protected void updateStatesForWindowSelectionMode() {
+    // enable/disable the zoom functionality
+    setMouseZoomable( windowSelectionMode == WindowSelectionMode.ZOOM_IN, getFillZoomRectangle() );
+    // enable/disable the selection functionality
+    if ( selectionTracker != null )
+      selectionTracker.setEnabled( windowSelectionMode == WindowSelectionMode.SELECT );
+  }
+  
+  /**
+   * Sets the behavior of the chart panel on window selections via mouse.
+   * @param mode new selection mode
+   */
+  public void setWindowSelectionMode(WindowSelectionMode mode) {
+    this.windowSelectionMode = mode;
+    updateStatesForWindowSelectionMode();
+  }
+
+  /**
+   * Returns the behavior of the chart panel on window selections via mouse.
+   * @param mode new selection mode
+   */
+  public WindowSelectionMode getWindowSelectionMode() {
+    return this.windowSelectionMode; 
+  }
+  
+  /**
+   * Ignores the event if the window selection mode is not
+   * {@link WindowSelectionMode#ZOOM_IN}, to avoid conflicts
+   * between the two listeners.
+   */
+  @Override
+  public void mouseDragged(MouseEvent e) {
+    if ( getWindowSelectionMode() != WindowSelectionMode.ZOOM_IN )
+      return;
+    super.mouseDragged(e);
+  }
+
+  /**
+   * Ignores the event if the window selection mode is not
+   * {@link WindowSelectionMode#ZOOM_IN}, to avoid conflicts
+   * between the two listeners.
+   */
+  @Override
+  public void mouseMoved(MouseEvent e) {
+    if ( getWindowSelectionMode() != WindowSelectionMode.ZOOM_IN )
+      return;
+    super.mouseMoved(e);
+  }
+
+}

Modified: trunk/src/schmitzm/jfree/chart/renderer/SelectionRenderer.java
===================================================================
--- trunk/src/schmitzm/jfree/chart/renderer/SelectionRenderer.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/chart/renderer/SelectionRenderer.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,35 +1,54 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.jfree.chart.renderer;
-
-import java.awt.Paint;
-
-import schmitzm.jfree.chart.selection.DatasetSelectionModel;
-import schmitzm.jfree.chart.selection.DatasetSelectionModelProvider;
-
-/**
- * This interface defines methods for all chart renderer which differ
- * between selected and unselected data. Selected data is rendered in
- * a highlighted way. 
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- */
-public interface SelectionRenderer<E extends DatasetSelectionModel<?>> extends DatasetSelectionModelProvider<E>{
-  /**
-   * Returns the color, the selected data is rendered with.
-   */
-  public Paint getSelectionPaint();
-
-  /**
-   * Sets the color, the selected data is rendered with.
-   * @param paint color for the selected data
-   */
-  public void setSelectionPaint(Paint paint);
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.jfree.chart.renderer;
+
+import java.awt.Paint;
+
+import schmitzm.jfree.chart.selection.DatasetSelectionModel;
+import schmitzm.jfree.chart.selection.DatasetSelectionModelProvider;
+
+/**
+ * This interface defines methods for all chart renderer which differ
+ * between selected and unselected data. Selected data is rendered in
+ * a highlighted way. 
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ */
+public interface SelectionRenderer<E extends DatasetSelectionModel<?>> extends DatasetSelectionModelProvider<E>{
+  /**
+   * Returns the color, the selected data is rendered with.
+   */
+  public Paint getSelectionPaint();
+
+  /**
+   * Sets the color, the selected data is rendered with.
+   * @param paint color for the selected data
+   */
+  public void setSelectionPaint(Paint paint);
+}

Modified: trunk/src/schmitzm/jfree/chart/renderer/SelectionXYLineAndShapeRenderer.java
===================================================================
--- trunk/src/schmitzm/jfree/chart/renderer/SelectionXYLineAndShapeRenderer.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/chart/renderer/SelectionXYLineAndShapeRenderer.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,225 +1,243 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.jfree.chart.renderer;
-
-import java.awt.Color;
-import java.awt.Graphics2D;
-import java.awt.Paint;
-import java.awt.geom.Rectangle2D;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.log4j.Logger;
-import org.jfree.chart.axis.ValueAxis;
-import org.jfree.chart.plot.CrosshairState;
-import org.jfree.chart.plot.Plot;
-import org.jfree.chart.plot.PlotRenderingInfo;
-import org.jfree.chart.plot.XYPlot;
-import org.jfree.chart.renderer.xy.XYItemRendererState;
-import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
-import org.jfree.data.general.Dataset;
-import org.jfree.data.xy.XYDataset;
-
-import schmitzm.jfree.chart.selection.SeriesDatasetSelectionModel;
-import schmitzm.lang.LangUtil;
-
-/**
- * Extends the {@link XYLineAndShapeRenderer} with the
- * {@link SelectionRenderer} functionality. Additionally redefines
- * the {@link #drawItem(Graphics2D, XYItemRendererState, Rectangle2D, PlotRenderingInfo, XYPlot, ValueAxis, ValueAxis, XYDataset, int, int, CrosshairState, int)}
- * method to realize the highlight rendering of the selected
- * items.<br>
- * <b>Note:</b><br>
- * An adequate {@link SeriesDatasetSelectionModel} is automatically
- * created when a new {@link Plot} is set. Manually calling {@link #setSelectionModel(SeriesDatasetSelectionModel)}
- * is usually not necessary. Overwrite {@link #createAndSetSelectionModel()} to
- * avoid this behavior.<br>
- * If no selection model is set, the behavior of this renderer is exactly
- * like the super class.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- */
-public class SelectionXYLineAndShapeRenderer extends XYLineAndShapeRenderer implements SelectionRenderer<SeriesDatasetSelectionModel> {
-  /** Used for log and debug messages. */
-  protected Logger LOGGER = LangUtil.createLogger(this);
-
-  /** Holds the selection model, the renderer uses to determine whether a
-   *  data item is selected or not. */
-  protected SeriesDatasetSelectionModel selectionModel = null;
-
-  /** Holds the selection color for each series. */
-  protected Map<Integer,Paint> selectionPaint = new HashMap<Integer, Paint>();
-  
-  /**
-   * Creates a new renderer.
-   */
-  public SelectionXYLineAndShapeRenderer() {
-    super();
-    init();
-  }
-
-  /**
-   * Creates a new renderer.
-   * @param lines   indicates whether lines are rendered between the data points
-   * @param shapes  indicates whether shapes are rendered under the data line
-   */
-  public SelectionXYLineAndShapeRenderer(boolean lines, boolean shapes) {
-    super(lines, shapes);
-    init();
-  }
-  
-  /**
-   * Called by every constructor to initialize the extensions 
-   * of this renderer.
-   */
-  protected void init() {
-    // set a default highlight color for the primary series
-    setSelectionPaint(Color.YELLOW);
-  }
- 
-  /**
-   * Sets the selection model the renderer uses to determine whether
-   * a data item is selected or not.
-   * @param model the selection model
-   */
-  public void setSelectionModel(SeriesDatasetSelectionModel model) {
-    this.selectionModel = model;
-  }
-  
-  /**
-   * Returns the selection model the renderer uses to determine whether
-   * a data item is selected or not.
-   */
-  public SeriesDatasetSelectionModel getSelectionModel() {
-    return selectionModel;
-  }
-  
-  /**
-   * Creates and sets an adequate {@link SeriesDatasetSelectionModel}
-   * according to the {@link Dataset} of the current {@link Plot}. Automatically
-   * called by {@link #setPlot(XYPlot)}.<br>
-   * Sets the selection model to {@code null} if the renderer is not
-   * connected to a plot or the plot contains no dataset.
-   * @see #createSelectionModel(XYDataset) 
-   */
-  public void createAndSetSelectionModel() {
-    XYPlot    plot       = getPlot();
-    XYDataset newDataset = (plot == null) ? null : plot.getDataset();
-    if ( getSelectionModel() == null || getSelectionModel().getDataset() != newDataset )
-      setSelectionModel( newDataset != null ? createSelectionModel(newDataset) : null );
-  }
-
-  /**
-   * Creates an adequate {@link SeriesDatasetSelectionModel}
-   * according to the given {@link Dataset}. Subclasses can overwrite this
-   * method to create an alternative {@link SeriesDatasetSelectionModel}.
-   */
-  public SeriesDatasetSelectionModel createSelectionModel(XYDataset dataset) {
-    return new SeriesDatasetSelectionModel(dataset);
-  }
-
-  /**
-   * Returns the color, the selected data <b>of the primary series</b>
-   * is rendered with.
-   * @return {@code null} if no selection color is defined
-   *         for the series
-   */
-  public Paint getSelectionPaint() {
-    return getSelectionPaint(0);
-  }
-
-  /**
-   * Sets the color, the selected data <b>of the primary series</b>
-   * is rendered with.
-   * @param paint color for the selected data
-   */
-  public void setSelectionPaint(Paint paint) {
-    setSelectionPaint(0, paint);
-  }
-
-  /**
-   * Returns the color, the selected data is rendered with.
-   * @param series the data series
-   * @return {@code null} if no selection color is defined
-   *         for the series
-   */
-  public Paint getSelectionPaint(int series) {
-    return selectionPaint.get(series);
-  }
-
-  /**
-   * Sets the color, the selected data is rendered with.
-   * @param series the data series
-   * @param paint color for the selected data
-   */
-  public void setSelectionPaint(int series, Paint paint) {
-    selectionPaint.put(series, paint);
-  }
-  
-  /**
-   * Creates and sets a new {@link SeriesDatasetSelectionModel}, if no selection model
-   * is set yet, or the selection model's dataset differs from the dataset of the
-   * new plot.
-   * @param plot the plot rendered by this renderer
-   */
-  public void setPlot(XYPlot plot) {
-    super.setPlot(plot);
-    createAndSetSelectionModel();
-  }
-
-  /**
-   * Sets the rendering color (temporary for the rendering process) to the
-   * {@linkplain #getSelectionPaint(int) highlight color}, if the item is
-   * defined as selected (by the {@linkplain #getSelectionModel() selection model}).
-   */
-  public void drawItem(Graphics2D g,
-      XYItemRendererState state,
-      Rectangle2D dataArea,
-      PlotRenderingInfo info,
-      XYPlot plot,
-      ValueAxis domainAxis,
-      ValueAxis rangeAxis,
-      XYDataset dataset,
-      int series,
-      int item,
-      CrosshairState crosshairState,
-      int pass) {
-
-    // Save the normal rendering color
-    Paint origPaint = getSeriesPaint(series);
-
-    // if selection model and color is set and the item is selected
-    // the hightlighting selection color is (temporary) set for the
-    // rendering process
-    if ( getSelectionModel() != null ) {
-      Paint selPaint  = getSelectionPaint(series);
-      if ( selPaint != null ) {
-        if ( item == 80 ) {
-          item ++;
-          item --;
-        }
-        Comparable seriesKey = dataset.getSeriesKey(series);
-        if ( selectionModel.isItemSelected(seriesKey, item) )
-          setSeriesPaint( series, selPaint, false );
-        else
-          setSeriesPaint( series, origPaint, false );
-      } else
-        LOGGER.warn("No selection paint set for series "+series+". Series is rendererd normally.");
-    } else
-      LOGGER.debug("No selection model set for renderer. All series rendererd normally.");
-    
-    // rendering
-    super.drawItem(g, state, dataArea, info, plot, domainAxis, rangeAxis, dataset, series, item, crosshairState, pass);
-    
-    // reset the original rendering color
-    setSeriesPaint( series, origPaint, false );
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.jfree.chart.renderer;
+
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.Paint;
+import java.awt.geom.Rectangle2D;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.log4j.Logger;
+import org.jfree.chart.axis.ValueAxis;
+import org.jfree.chart.plot.CrosshairState;
+import org.jfree.chart.plot.Plot;
+import org.jfree.chart.plot.PlotRenderingInfo;
+import org.jfree.chart.plot.XYPlot;
+import org.jfree.chart.renderer.xy.XYItemRendererState;
+import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
+import org.jfree.data.general.Dataset;
+import org.jfree.data.xy.XYDataset;
+
+import schmitzm.jfree.chart.selection.SeriesDatasetSelectionModel;
+import schmitzm.lang.LangUtil;
+
+/**
+ * Extends the {@link XYLineAndShapeRenderer} with the
+ * {@link SelectionRenderer} functionality. Additionally redefines
+ * the {@link #drawItem(Graphics2D, XYItemRendererState, Rectangle2D, PlotRenderingInfo, XYPlot, ValueAxis, ValueAxis, XYDataset, int, int, CrosshairState, int)}
+ * method to realize the highlight rendering of the selected
+ * items.<br>
+ * <b>Note:</b><br>
+ * An adequate {@link SeriesDatasetSelectionModel} is automatically
+ * created when a new {@link Plot} is set. Manually calling {@link #setSelectionModel(SeriesDatasetSelectionModel)}
+ * is usually not necessary. Overwrite {@link #createAndSetSelectionModel()} to
+ * avoid this behavior.<br>
+ * If no selection model is set, the behavior of this renderer is exactly
+ * like the super class.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ */
+public class SelectionXYLineAndShapeRenderer extends XYLineAndShapeRenderer implements SelectionRenderer<SeriesDatasetSelectionModel> {
+  /** Used for log and debug messages. */
+  protected Logger LOGGER = LangUtil.createLogger(this);
+
+  /** Holds the selection model, the renderer uses to determine whether a
+   *  data item is selected or not. */
+  protected SeriesDatasetSelectionModel selectionModel = null;
+
+  /** Holds the selection color for each series. */
+  protected Map<Integer,Paint> selectionPaint = new HashMap<Integer, Paint>();
+  
+  /**
+   * Creates a new renderer.
+   */
+  public SelectionXYLineAndShapeRenderer() {
+    super();
+    init();
+  }
+
+  /**
+   * Creates a new renderer.
+   * @param lines   indicates whether lines are rendered between the data points
+   * @param shapes  indicates whether shapes are rendered under the data line
+   */
+  public SelectionXYLineAndShapeRenderer(boolean lines, boolean shapes) {
+    super(lines, shapes);
+    init();
+  }
+  
+  /**
+   * Called by every constructor to initialize the extensions 
+   * of this renderer.
+   */
+  protected void init() {
+    // set a default highlight color for the primary series
+    setSelectionPaint(Color.YELLOW);
+  }
+ 
+  /**
+   * Sets the selection model the renderer uses to determine whether
+   * a data item is selected or not.
+   * @param model the selection model
+   */
+  public void setSelectionModel(SeriesDatasetSelectionModel model) {
+    this.selectionModel = model;
+  }
+  
+  /**
+   * Returns the selection model the renderer uses to determine whether
+   * a data item is selected or not.
+   */
+  public SeriesDatasetSelectionModel getSelectionModel() {
+    return selectionModel;
+  }
+  
+  /**
+   * Creates and sets an adequate {@link SeriesDatasetSelectionModel}
+   * according to the {@link Dataset} of the current {@link Plot}. Automatically
+   * called by {@link #setPlot(XYPlot)}.<br>
+   * Sets the selection model to {@code null} if the renderer is not
+   * connected to a plot or the plot contains no dataset.
+   * @see #createSelectionModel(XYDataset) 
+   */
+  public void createAndSetSelectionModel() {
+    XYPlot    plot       = getPlot();
+    XYDataset newDataset = (plot == null) ? null : plot.getDataset();
+    if ( getSelectionModel() == null || getSelectionModel().getDataset() != newDataset )
+      setSelectionModel( newDataset != null ? createSelectionModel(newDataset) : null );
+  }
+
+  /**
+   * Creates an adequate {@link SeriesDatasetSelectionModel}
+   * according to the given {@link Dataset}. Subclasses can overwrite this
+   * method to create an alternative {@link SeriesDatasetSelectionModel}.
+   */
+  public SeriesDatasetSelectionModel createSelectionModel(XYDataset dataset) {
+    return new SeriesDatasetSelectionModel(dataset);
+  }
+
+  /**
+   * Returns the color, the selected data <b>of the primary series</b>
+   * is rendered with.
+   * @return {@code null} if no selection color is defined
+   *         for the series
+   */
+  public Paint getSelectionPaint() {
+    return getSelectionPaint(0);
+  }
+
+  /**
+   * Sets the color, the selected data <b>of the primary series</b>
+   * is rendered with.
+   * @param paint color for the selected data
+   */
+  public void setSelectionPaint(Paint paint) {
+    setSelectionPaint(0, paint);
+  }
+
+  /**
+   * Returns the color, the selected data is rendered with.
+   * @param series the data series
+   * @return {@code null} if no selection color is defined
+   *         for the series
+   */
+  public Paint getSelectionPaint(int series) {
+    return selectionPaint.get(series);
+  }
+
+  /**
+   * Sets the color, the selected data is rendered with.
+   * @param series the data series
+   * @param paint color for the selected data
+   */
+  public void setSelectionPaint(int series, Paint paint) {
+    selectionPaint.put(series, paint);
+  }
+  
+  /**
+   * Creates and sets a new {@link SeriesDatasetSelectionModel}, if no selection model
+   * is set yet, or the selection model's dataset differs from the dataset of the
+   * new plot.
+   * @param plot the plot rendered by this renderer
+   */
+  public void setPlot(XYPlot plot) {
+    super.setPlot(plot);
+    createAndSetSelectionModel();
+  }
+
+  /**
+   * Sets the rendering color (temporary for the rendering process) to the
+   * {@linkplain #getSelectionPaint(int) highlight color}, if the item is
+   * defined as selected (by the {@linkplain #getSelectionModel() selection model}).
+   */
+  public void drawItem(Graphics2D g,
+      XYItemRendererState state,
+      Rectangle2D dataArea,
+      PlotRenderingInfo info,
+      XYPlot plot,
+      ValueAxis domainAxis,
+      ValueAxis rangeAxis,
+      XYDataset dataset,
+      int series,
+      int item,
+      CrosshairState crosshairState,
+      int pass) {
+
+    // Save the normal rendering color
+    Paint origPaint = getSeriesPaint(series);
+
+    // if selection model and color is set and the item is selected
+    // the hightlighting selection color is (temporary) set for the
+    // rendering process
+    if ( getSelectionModel() != null ) {
+      Paint selPaint  = getSelectionPaint(series);
+      if ( selPaint != null ) {
+        if ( item == 80 ) {
+          item ++;
+          item --;
+        }
+        Comparable seriesKey = dataset.getSeriesKey(series);
+        if ( selectionModel.isItemSelected(seriesKey, item) )
+          setSeriesPaint( series, selPaint, false );
+        else
+          setSeriesPaint( series, origPaint, false );
+      } else
+        LOGGER.warn("No selection paint set for series "+series+". Series is rendererd normally.");
+    } else
+      LOGGER.debug("No selection model set for renderer. All series rendererd normally.");
+    
+    // rendering
+    super.drawItem(g, state, dataArea, info, plot, domainAxis, rangeAxis, dataset, series, item, crosshairState, pass);
+    
+    // reset the original rendering color
+    setSeriesPaint( series, origPaint, false );
+  }
+}

Modified: trunk/src/schmitzm/jfree/chart/selection/AbstractDatasetSelectionModel.java
===================================================================
--- trunk/src/schmitzm/jfree/chart/selection/AbstractDatasetSelectionModel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/chart/selection/AbstractDatasetSelectionModel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,139 +1,158 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.jfree.chart.selection;
-
-import java.util.Vector;
-
-import org.apache.log4j.Logger;
-import org.jfree.data.general.Dataset;
-import org.jfree.data.general.DatasetChangeListener;
-import org.jfree.data.general.SeriesDataset;
-
-import schmitzm.lang.LangUtil;
-
-/**
- * This class is a general implementation of {@link DatasetSelectionModel} and maintains whether
- * items of a {@link Dataset} are selected in a chart or not. The model connects to
- * the {@link Dataset} as {@link DatasetChangeListener} to recognize the moment a
- * series is removed. Subclasses must implement
- * {@link #datasetChanged(org.jfree.data.general.DatasetChangeEvent)} to react with an
- * automatic unselect.
- * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- */
-public abstract class AbstractDatasetSelectionModel<E extends Dataset> implements DatasetSelectionModel<E> {
-  /** {@link Logger} to log waring, debug or error messages. */
-  protected Logger LOGGER = LangUtil.createLogger(this);
-
-  /** Holds the {@link Dataset} whose data can be selected. */
-  protected E dataset = null;
-  
-  /** Holds the listeners to the {@link DatasetSelectionModel}. */
-  protected Vector<DatasetSelectionListener> listeners = new Vector<DatasetSelectionListener>();
-
-  /** Indicates whether a selection change is a part of multiple
-   *  changes. If {@code true} {@link #refreshSelection()} has NO effect
-   *  until {@link #setValueIsAdjusting(boolean) setValueIsAdjusting(false)}
-   *  is called. */
-  private boolean valueIsAdjusting = false;
-
-  /**
-   * Creates a new selection model.
-   * @param dataset {@link Dataset} whose data can be selected
-   */
-  public AbstractDatasetSelectionModel(E dataset) {
-    this.dataset = dataset;
-    dataset.addChangeListener(this);
-  }
-  
-  /**
-   * Creates a {@link AbstractDatasetSelectionModel} for a {@link Dataset}.
-   * @param dataset a dataset
-   * @return {@code null} if selection is not supported for dataset
-   */
-  public static AbstractDatasetSelectionModel<?> createInstanceFor(Dataset dataset) {
-    if ( dataset instanceof SeriesDataset )
-      return new SeriesDatasetSelectionModel((SeriesDataset)dataset);
-    return null;
-  }
-
-  /**
-   * Returns the {@link Dataset} whose data can be selected. 
-   */
-  public E getDataset() {
-    return dataset;
-  }
-  
-  /**
-   * Clears the selection.
-   */
-  public abstract void clearSelection();
-  
-  /**
-   * Adds a listener which will be informed about changed on the
-   * selection model.
-   * @param listener the listener to be added
-   */
-  public void addSelectionListener(DatasetSelectionListener listener) {
-    listeners.add(listener);
-  }
-  
-  /**
-   * Removes a listener from the selection model.
-   * @param listener the listener to be remove
-   */
-  public void removeSelectionListener(DatasetSelectionListener listener) {
-    listeners.remove(listener);
-  }
-
-  /**
-   * Returns whether the current selection change is a part of multiple
-   * changes. If {@code true} {@link #refreshSelection()} has no effect
-   * and no {@link DatasetSelectionChangeEvent} is fired until
-   * {@link #setValueIsAdjusting(boolean) setValueIsAdjusting(false)}
-   * is called.
-   */
-  public boolean getValueIsAdjusting() {
-    return this.valueIsAdjusting;
-  }
-
-  /**
-   * Sets whether the following selection changes are part of multiple
-   * changes. If {@code true} {@link #refreshSelection()} has no effect
-   * and no {@link DatasetSelectionChangeEvent} event is fired.
-   * If the value is set from {@code true} to {@code false} an automatic
-   * refresh is initiated.
-   * @see #refreshSelection()
-   */
-  public void setValueIsAdjusting(boolean valueIsAdjusting) {
-    if ( valueIsAdjusting != this.valueIsAdjusting ) {
-      this.valueIsAdjusting = valueIsAdjusting;
-      if ( !this.valueIsAdjusting )
-        refreshSelection();
-    }
-  }
-  
-  /**
-   * Informs all listeners about a general selection change. Does nothing
-   * if {@link #getValueIsAdjusting()} is {@code true}.
-   */
-  public void refreshSelection() {
-    if ( !getValueIsAdjusting() )
-      for (DatasetSelectionListener l : listeners)
-        l.selectionChanged( createSelectionChangeEvent() );
-  }
-  
-  /**
-   * Creates a {@link DatasetSelectionChangeEvent}.
-   */
-  protected DatasetSelectionChangeEvent createSelectionChangeEvent() {
-    return new DatasetSelectionChangeEvent(this);
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.jfree.chart.selection;
+
+import java.util.Vector;
+
+import org.apache.log4j.Logger;
+import org.jfree.data.general.Dataset;
+import org.jfree.data.general.DatasetChangeListener;
+import org.jfree.data.general.SeriesDataset;
+
+import schmitzm.lang.LangUtil;
+
+/**
+ * This class is a general implementation of {@link DatasetSelectionModel} and maintains whether
+ * items of a {@link Dataset} are selected in a chart or not. The model connects to
+ * the {@link Dataset} as {@link DatasetChangeListener} to recognize the moment a
+ * series is removed. Subclasses must implement
+ * {@link #datasetChanged(org.jfree.data.general.DatasetChangeEvent)} to react with an
+ * automatic unselect.
+ * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ */
+public abstract class AbstractDatasetSelectionModel<E extends Dataset> implements DatasetSelectionModel<E> {
+  /** {@link Logger} to log waring, debug or error messages. */
+  protected Logger LOGGER = LangUtil.createLogger(this);
+
+  /** Holds the {@link Dataset} whose data can be selected. */
+  protected E dataset = null;
+  
+  /** Holds the listeners to the {@link DatasetSelectionModel}. */
+  protected Vector<DatasetSelectionListener> listeners = new Vector<DatasetSelectionListener>();
+
+  /** Indicates whether a selection change is a part of multiple
+   *  changes. If {@code true} {@link #refreshSelection()} has NO effect
+   *  until {@link #setValueIsAdjusting(boolean) setValueIsAdjusting(false)}
+   *  is called. */
+  private boolean valueIsAdjusting = false;
+
+  /**
+   * Creates a new selection model.
+   * @param dataset {@link Dataset} whose data can be selected
+   */
+  public AbstractDatasetSelectionModel(E dataset) {
+    this.dataset = dataset;
+    dataset.addChangeListener(this);
+  }
+  
+  /**
+   * Creates a {@link AbstractDatasetSelectionModel} for a {@link Dataset}.
+   * @param dataset a dataset
+   * @return {@code null} if selection is not supported for dataset
+   */
+  public static AbstractDatasetSelectionModel<?> createInstanceFor(Dataset dataset) {
+    if ( dataset instanceof SeriesDataset )
+      return new SeriesDatasetSelectionModel((SeriesDataset)dataset);
+    return null;
+  }
+
+  /**
+   * Returns the {@link Dataset} whose data can be selected. 
+   */
+  public E getDataset() {
+    return dataset;
+  }
+  
+  /**
+   * Clears the selection.
+   */
+  public abstract void clearSelection();
+  
+  /**
+   * Adds a listener which will be informed about changed on the
+   * selection model.
+   * @param listener the listener to be added
+   */
+  public void addSelectionListener(DatasetSelectionListener listener) {
+    listeners.add(listener);
+  }
+  
+  /**
+   * Removes a listener from the selection model.
+   * @param listener the listener to be remove
+   */
+  public void removeSelectionListener(DatasetSelectionListener listener) {
+    listeners.remove(listener);
+  }
+
+  /**
+   * Returns whether the current selection change is a part of multiple
+   * changes. If {@code true} {@link #refreshSelection()} has no effect
+   * and no {@link DatasetSelectionChangeEvent} is fired until
+   * {@link #setValueIsAdjusting(boolean) setValueIsAdjusting(false)}
+   * is called.
+   */
+  public boolean getValueIsAdjusting() {
+    return this.valueIsAdjusting;
+  }
+
+  /**
+   * Sets whether the following selection changes are part of multiple
+   * changes. If {@code true} {@link #refreshSelection()} has no effect
+   * and no {@link DatasetSelectionChangeEvent} event is fired.
+   * If the value is set from {@code true} to {@code false} an automatic
+   * refresh is initiated.
+   * @see #refreshSelection()
+   */
+  public void setValueIsAdjusting(boolean valueIsAdjusting) {
+    if ( valueIsAdjusting != this.valueIsAdjusting ) {
+      this.valueIsAdjusting = valueIsAdjusting;
+      if ( !this.valueIsAdjusting )
+        refreshSelection();
+    }
+  }
+  
+  /**
+   * Informs all listeners about a general selection change. Does nothing
+   * if {@link #getValueIsAdjusting()} is {@code true}.
+   */
+  public void refreshSelection() {
+    if ( !getValueIsAdjusting() )
+      for (DatasetSelectionListener l : listeners)
+        l.selectionChanged( createSelectionChangeEvent() );
+  }
+  
+  /**
+   * Creates a {@link DatasetSelectionChangeEvent}.
+   */
+  protected DatasetSelectionChangeEvent createSelectionChangeEvent() {
+    return new DatasetSelectionChangeEvent(this);
+  }
+}

Modified: trunk/src/schmitzm/jfree/chart/selection/DatasetSelectionChangeEvent.java
===================================================================
--- trunk/src/schmitzm/jfree/chart/selection/DatasetSelectionChangeEvent.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/chart/selection/DatasetSelectionChangeEvent.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,36 +1,55 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.jfree.chart.selection;
-
-import javax.swing.event.ChangeEvent;
-
-/**
- * This event indicates a change on a dataset selection.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- */
-public class DatasetSelectionChangeEvent extends ChangeEvent {
-  
-  /**
-   * Creates a new event.
-   * @param source
-   * @param selModel the selection model
-   */
-  public DatasetSelectionChangeEvent(DatasetSelectionModel<?> source) {
-    super(source);
-  }
-  
-  /**
-   * Returns the initiating {@link DatasetSelectionModel}.
-   */
-  public DatasetSelectionModel<?> getSource() {
-    return (DatasetSelectionModel<?>)super.getSource();
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.jfree.chart.selection;
+
+import javax.swing.event.ChangeEvent;
+
+/**
+ * This event indicates a change on a dataset selection.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ */
+public class DatasetSelectionChangeEvent extends ChangeEvent {
+  
+  /**
+   * Creates a new event.
+   * @param source
+   * @param selModel the selection model
+   */
+  public DatasetSelectionChangeEvent(DatasetSelectionModel<?> source) {
+    super(source);
+  }
+  
+  /**
+   * Returns the initiating {@link DatasetSelectionModel}.
+   */
+  public DatasetSelectionModel<?> getSource() {
+    return (DatasetSelectionModel<?>)super.getSource();
+  }
+}

Modified: trunk/src/schmitzm/jfree/chart/selection/DatasetSelectionListener.java
===================================================================
--- trunk/src/schmitzm/jfree/chart/selection/DatasetSelectionListener.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/chart/selection/DatasetSelectionListener.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,23 +1,41 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.jfree.chart.selection;
-
-/**
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- */
-public interface DatasetSelectionListener {
-  /**
-   * Called when the selection of a {@link DatasetSelectionModel} has changed.
-   * @param e the event
-   */
-  public void selectionChanged(DatasetSelectionChangeEvent e);
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.jfree.chart.selection;
+
+/**
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ */
+public interface DatasetSelectionListener {
+  /**
+   * Called when the selection of a {@link DatasetSelectionModel} has changed.
+   * @param e the event
+   */
+  public void selectionChanged(DatasetSelectionChangeEvent e);
+}

Modified: trunk/src/schmitzm/jfree/chart/selection/DatasetSelectionModel.java
===================================================================
--- trunk/src/schmitzm/jfree/chart/selection/DatasetSelectionModel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/chart/selection/DatasetSelectionModel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,71 +1,90 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.jfree.chart.selection;
-
-import org.jfree.data.general.Dataset;
-import org.jfree.data.general.DatasetChangeListener;
-
-/**
- * This selection model maintains whether items of a {@link Dataset} are selected
- * in a chart or not. The model connects to the {@link Dataset} as {@link DatasetChangeListener}
- * to recognize the moment a series is removed. Subclasses must implement
- * {@link #datasetChanged(org.jfree.data.general.DatasetChangeEvent)} to react with an
- * automatic unselect.
- * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- */
-public interface DatasetSelectionModel<E extends Dataset> extends DatasetChangeListener {
-  /**
-   * Returns the {@link Dataset} whose data can be selected. 
-   */
-  public E getDataset();
-  
-  /**
-   * Clears the selection.
-   */
-  public void clearSelection();
-  
-  /**
-   * Adds a listener which will be informed about changed on the
-   * selection model.
-   * @param listener the listener to be added
-   */
-  public void addSelectionListener(DatasetSelectionListener listener);
-  
-  /**
-   * Removes a listener from the selection model.
-   * @param listener the listener to be remove
-   */
-  public void removeSelectionListener(DatasetSelectionListener listener);
-  
-  /**
-   * Returns whether the current selection change is a part of multiple
-   * changes. If {@code true} {@link #refreshSelection()} has no effect
-   * and no {@link DatasetSelectionChangeEvent} is fired until
-   * {@link #setValueIsAdjusting(boolean) setValueIsAdjusting(false)}
-   * is called.
-   */
-  public boolean getValueIsAdjusting();
-
-  /**
-   * Sets whether the following selection changes are part of multiple
-   * changes. If {@code true} {@link #refreshSelection()} has no effect
-   * and no {@link DatasetSelectionChangeEvent} event is fired.
-   * If the value is set from {@code true} to {@code false} an automatic
-   * refresh is initiated.
-   * @see #refreshSelection()
-   */
-  public void setValueIsAdjusting(boolean valueIsAdjusting);
-
-  /**
-   * Informs all listeners about a general selection change.
-   */
-  public void refreshSelection();
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.jfree.chart.selection;
+
+import org.jfree.data.general.Dataset;
+import org.jfree.data.general.DatasetChangeListener;
+
+/**
+ * This selection model maintains whether items of a {@link Dataset} are selected
+ * in a chart or not. The model connects to the {@link Dataset} as {@link DatasetChangeListener}
+ * to recognize the moment a series is removed. Subclasses must implement
+ * {@link #datasetChanged(org.jfree.data.general.DatasetChangeEvent)} to react with an
+ * automatic unselect.
+ * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ */
+public interface DatasetSelectionModel<E extends Dataset> extends DatasetChangeListener {
+  /**
+   * Returns the {@link Dataset} whose data can be selected. 
+   */
+  public E getDataset();
+  
+  /**
+   * Clears the selection.
+   */
+  public void clearSelection();
+  
+  /**
+   * Adds a listener which will be informed about changed on the
+   * selection model.
+   * @param listener the listener to be added
+   */
+  public void addSelectionListener(DatasetSelectionListener listener);
+  
+  /**
+   * Removes a listener from the selection model.
+   * @param listener the listener to be remove
+   */
+  public void removeSelectionListener(DatasetSelectionListener listener);
+  
+  /**
+   * Returns whether the current selection change is a part of multiple
+   * changes. If {@code true} {@link #refreshSelection()} has no effect
+   * and no {@link DatasetSelectionChangeEvent} is fired until
+   * {@link #setValueIsAdjusting(boolean) setValueIsAdjusting(false)}
+   * is called.
+   */
+  public boolean getValueIsAdjusting();
+
+  /**
+   * Sets whether the following selection changes are part of multiple
+   * changes. If {@code true} {@link #refreshSelection()} has no effect
+   * and no {@link DatasetSelectionChangeEvent} event is fired.
+   * If the value is set from {@code true} to {@code false} an automatic
+   * refresh is initiated.
+   * @see #refreshSelection()
+   */
+  public void setValueIsAdjusting(boolean valueIsAdjusting);
+
+  /**
+   * Informs all listeners about a general selection change.
+   */
+  public void refreshSelection();
+}

Modified: trunk/src/schmitzm/jfree/chart/selection/DatasetSelectionModelProvider.java
===================================================================
--- trunk/src/schmitzm/jfree/chart/selection/DatasetSelectionModelProvider.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/chart/selection/DatasetSelectionModelProvider.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,39 +1,58 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.jfree.chart.selection;
-
-import org.jfree.chart.plot.Plot;
-import org.jfree.data.general.Dataset;
-
-/**
- * Interface for all objects (especially {@link Plot Plots}) which provide
- * a {@link AbstractDatasetSelectionModel}.
- * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- */
-public interface DatasetSelectionModelProvider<E extends DatasetSelectionModel<?>> {
-  /**
-   * Returns the selection model for the (primary) {@link Dataset}. 
-   */
-  public E getSelectionModel();
-
-  /**
-   * Sets the selection model for the (primary) {@link Dataset}. 
-   * @param model   the new selection model
-   */
-  public void setSelectionModel(E model);
-  
-//  /**
-//   * Creates an adequate selection model for a dataset. An implementation should
-//   * simply call {@link DatasetSelectionModel#createInstanceFor(Dataset)}.
-//   * @param dataset a dataset
-//   */
-//  public E createSelectionModel(Dataset dataset);
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.jfree.chart.selection;
+
+import org.jfree.chart.plot.Plot;
+import org.jfree.data.general.Dataset;
+
+/**
+ * Interface for all objects (especially {@link Plot Plots}) which provide
+ * a {@link AbstractDatasetSelectionModel}.
+ * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ */
+public interface DatasetSelectionModelProvider<E extends DatasetSelectionModel<?>> {
+  /**
+   * Returns the selection model for the (primary) {@link Dataset}. 
+   */
+  public E getSelectionModel();
+
+  /**
+   * Sets the selection model for the (primary) {@link Dataset}. 
+   * @param model   the new selection model
+   */
+  public void setSelectionModel(E model);
+  
+//  /**
+//   * Creates an adequate selection model for a dataset. An implementation should
+//   * simply call {@link DatasetSelectionModel#createInstanceFor(Dataset)}.
+//   * @param dataset a dataset
+//   */
+//  public E createSelectionModel(Dataset dataset);
+}

Modified: trunk/src/schmitzm/jfree/chart/selection/SeriesDatasetSelectionModel.java
===================================================================
--- trunk/src/schmitzm/jfree/chart/selection/SeriesDatasetSelectionModel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/chart/selection/SeriesDatasetSelectionModel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,124 +1,143 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.jfree.chart.selection;
-
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-
-import org.jfree.data.general.Dataset;
-import org.jfree.data.general.DatasetChangeEvent;
-import org.jfree.data.general.SeriesDataset;
-
-/**
- * This selection model maintains whether items of a {@link SeriesDataset} are selected
- * in a chart or not.
- * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- */
-public class SeriesDatasetSelectionModel extends AbstractDatasetSelectionModel<SeriesDataset> {
-  /** Contains a {@link Set} for each series. In each of these sets the
-   *  indices of the selected items are stored. */
-  protected Map<Comparable,Set<Integer>> selectedSeriesIdx = new HashMap<Comparable,Set<Integer>>();
-
-  /**
-   * Creates a new selection model.
-   * @param dataset {@link Dataset} whose data can be selected
-   */
-  public SeriesDatasetSelectionModel(SeriesDataset dataset) {
-    super(dataset);
-  }
-  
-  /**
-   * Checks if an series item is selected.
-   * @param seriesKey key of the series
-   * @param item      index of the item in the series
-   */
-  public boolean isItemSelected(Comparable seriesKey, int item) {
-    // determine the set for the series
-    Set<Integer> selectedIdx = selectedSeriesIdx.get(seriesKey);
-    // check whether item is selected
-    return selectedIdx != null && selectedIdx.contains(item);  
-  }
-  
-  /**
-   * Sets whether a series item is selected or not.
-   * @param seriesKey key of the series
-   * @param item      index of the item in the series
-   * @param selected  flag to (de)select the item
-   */
-  public void setItemSelected(Comparable seriesKey, int item, boolean selected) {
-    // determine the set for the series
-    Set<Integer> selectedIdx = selectedSeriesIdx.get(seriesKey);
-    // create a set for the series if not yet existing
-    if ( selectedIdx == null ) {
-      selectedIdx = new HashSet<Integer>();
-      selectedSeriesIdx.put(seriesKey, selectedIdx);
-    }
-    // add/remove item index
-    if ( selected )
-      selectedIdx.add(item);
-    else
-      selectedIdx.remove(item);
-    
-    // inform all listeners about the selection change
-    refreshSelection();
-  }
-  
-  /**
-   * Changes the selection of a series item.
-   * @param seriesKey key of the series
-   * @param item      index of the item in the series
-   * @return {@code true} if the item changed to selected 
-   */
-  public boolean changeItemSelection(Comparable seriesKey, int item) {
-    boolean nowSelected = !isItemSelected(seriesKey, item);
-    setItemSelected(seriesKey, item, nowSelected);
-    return nowSelected;
-  }
-  
-  /**
-   * Clears the selection for all series.
-   */
-  public void clearSelection() {
-    // clear all series sets
-    for (Set<Integer> selectedIdx: selectedSeriesIdx.values())
-      selectedIdx.clear();
-    // clear the series map
-    selectedSeriesIdx.clear();
-    // inform all listeners about the selection change
-    refreshSelection();
-  }
-  
-  /**
-   * 
-   */
-  @Override
-  public void datasetChanged(DatasetChangeEvent event) {
-    if ( event.getDataset() != this.dataset ||
-         !(event.getDataset() instanceof SeriesDataset) )
-      return;
-    SeriesDataset changedDataset = (SeriesDataset)event.getDataset();
-      
-    // check whether all series are still present
-    for (Comparable seriesKey : selectedSeriesIdx.keySet())
-      // if series is no longer present, also remove series
-      // from selection model
-      if ( changedDataset.indexOf(seriesKey) < 0 ) {
-        // clear series set and remove series set
-        Set<Integer> selectedIdx = selectedSeriesIdx.get(seriesKey);
-        if ( selectedIdx != null )
-          selectedIdx.clear();
-        selectedSeriesIdx.remove(seriesKey);
-      }
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.jfree.chart.selection;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.jfree.data.general.Dataset;
+import org.jfree.data.general.DatasetChangeEvent;
+import org.jfree.data.general.SeriesDataset;
+
+/**
+ * This selection model maintains whether items of a {@link SeriesDataset} are selected
+ * in a chart or not.
+ * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ */
+public class SeriesDatasetSelectionModel extends AbstractDatasetSelectionModel<SeriesDataset> {
+  /** Contains a {@link Set} for each series. In each of these sets the
+   *  indices of the selected items are stored. */
+  protected Map<Comparable,Set<Integer>> selectedSeriesIdx = new HashMap<Comparable,Set<Integer>>();
+
+  /**
+   * Creates a new selection model.
+   * @param dataset {@link Dataset} whose data can be selected
+   */
+  public SeriesDatasetSelectionModel(SeriesDataset dataset) {
+    super(dataset);
+  }
+  
+  /**
+   * Checks if an series item is selected.
+   * @param seriesKey key of the series
+   * @param item      index of the item in the series
+   */
+  public boolean isItemSelected(Comparable seriesKey, int item) {
+    // determine the set for the series
+    Set<Integer> selectedIdx = selectedSeriesIdx.get(seriesKey);
+    // check whether item is selected
+    return selectedIdx != null && selectedIdx.contains(item);  
+  }
+  
+  /**
+   * Sets whether a series item is selected or not.
+   * @param seriesKey key of the series
+   * @param item      index of the item in the series
+   * @param selected  flag to (de)select the item
+   */
+  public void setItemSelected(Comparable seriesKey, int item, boolean selected) {
+    // determine the set for the series
+    Set<Integer> selectedIdx = selectedSeriesIdx.get(seriesKey);
+    // create a set for the series if not yet existing
+    if ( selectedIdx == null ) {
+      selectedIdx = new HashSet<Integer>();
+      selectedSeriesIdx.put(seriesKey, selectedIdx);
+    }
+    // add/remove item index
+    if ( selected )
+      selectedIdx.add(item);
+    else
+      selectedIdx.remove(item);
+    
+    // inform all listeners about the selection change
+    refreshSelection();
+  }
+  
+  /**
+   * Changes the selection of a series item.
+   * @param seriesKey key of the series
+   * @param item      index of the item in the series
+   * @return {@code true} if the item changed to selected 
+   */
+  public boolean changeItemSelection(Comparable seriesKey, int item) {
+    boolean nowSelected = !isItemSelected(seriesKey, item);
+    setItemSelected(seriesKey, item, nowSelected);
+    return nowSelected;
+  }
+  
+  /**
+   * Clears the selection for all series.
+   */
+  public void clearSelection() {
+    // clear all series sets
+    for (Set<Integer> selectedIdx: selectedSeriesIdx.values())
+      selectedIdx.clear();
+    // clear the series map
+    selectedSeriesIdx.clear();
+    // inform all listeners about the selection change
+    refreshSelection();
+  }
+  
+  /**
+   * 
+   */
+  @Override
+  public void datasetChanged(DatasetChangeEvent event) {
+    if ( event.getDataset() != this.dataset ||
+         !(event.getDataset() instanceof SeriesDataset) )
+      return;
+    SeriesDataset changedDataset = (SeriesDataset)event.getDataset();
+      
+    // check whether all series are still present
+    for (Comparable seriesKey : selectedSeriesIdx.keySet())
+      // if series is no longer present, also remove series
+      // from selection model
+      if ( changedDataset.indexOf(seriesKey) < 0 ) {
+        // clear series set and remove series set
+        Set<Integer> selectedIdx = selectedSeriesIdx.get(seriesKey);
+        if ( selectedIdx != null )
+          selectedIdx.clear();
+        selectedSeriesIdx.remove(seriesKey);
+      }
+  }
+
+}

Modified: trunk/src/schmitzm/jfree/chart/style/AbstractChartStyle.java
===================================================================
--- trunk/src/schmitzm/jfree/chart/style/AbstractChartStyle.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/chart/style/AbstractChartStyle.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,3 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 /*
  *  SDSS Framework - This file is part of the Spatial Decision Support System Framework Platform
  *
@@ -8,16 +37,16 @@
  *  Contact Information:                    info at andreas-enders.de
  */
 
-package schmitzm.jfree.chart.style;
-
+package schmitzm.jfree.chart.style;
+
 import java.awt.Color;
 import java.awt.Paint;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Vector;
 
-import org.apache.log4j.Category;
-import org.apache.log4j.Logger;
+import org.apache.log4j.Category;
+import org.apache.log4j.Logger;
 import org.jfree.chart.JFreeChart;
 import org.jfree.chart.axis.Axis;
 import org.jfree.chart.labels.CategoryToolTipGenerator;
@@ -40,14 +69,14 @@
 import schmitzm.jfree.JFreeChartUtil;
 import schmitzm.lang.LangUtil;
 import skrueger.i8n.Translation;
-
-/**
- * This class provides an abstract implementation for chart styles.
- * It implements the variables and methods for maintaining the type, the title(s)
- * and flags of the {@link ChartStyle} interface.
- * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
- * @version 1.0
- */
+
+/**
+ * This class provides an abstract implementation for chart styles.
+ * It implements the variables and methods for maintaining the type, the title(s)
+ * and flags of the {@link ChartStyle} interface.
+ * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
+ * @version 1.0
+ */
 public abstract class AbstractChartStyle implements ChartStyle {
   /** Tooltip generator used for XY-Charts. */
   protected XYToolTipGenerator TIPGEN_XY = new StandardXYToolTipGenerator();
@@ -58,80 +87,80 @@
   /** URL generator used for Category-Charts. */
   protected CategoryURLGenerator URLGEN_CAT = new StandardCategoryURLGenerator();
   
-  
-  /** Logger for this class */
-  protected final Category LOGGER = LangUtil.createLogger(this);
+  
+  /** Logger for this class */
+  protected final Category LOGGER = LangUtil.createLogger(this);
   /** Holds a (unique) ID for the style. */
-  protected String id = "";
-  /** Holds the chart type.
-   *  @see  ChartStyle#ChartType */
-  protected ChartType type = null;
-  /** Holds the chart title. */
+  protected String id = "";
+  /** Holds the chart type.
+   *  @see  ChartStyle#ChartType */
+  protected ChartType type = null;
+  /** Holds the chart title. */
   protected ChartLabelStyle titleStyle = new ChartLabelStyle();
   /** Holds a long description for the chart. */
   protected ChartLabelStyle descStyle = null;
   /** Holds the background color for the chart. */
   protected Color bgPaint = null;
   /** Stores whether a border is shown around the whole chart. */
-  protected boolean borderVisible = false;
-  /** Holds the styles of the chart axis. */
+  protected boolean borderVisible = false;
+  /** Holds the styles of the chart axis. */
   protected Map<Integer,ChartAxisStyle> axisStyle = new HashMap<Integer,ChartAxisStyle>();
   /** Holds the plot orientation (horizontal/vertical). */
-  protected PlotOrientation orientation = null;
-  /** Stores whether a legend is generated for the chart (Default: true). */
-  protected boolean legend = true;
-  /** Stores whether tooltips are generated for the chart data (Default: true). */
-  protected boolean tooltips = true;
-  /** Stores whether URLs are generated for the chart (Default: true). */
-  protected boolean urls = true;
+  protected PlotOrientation orientation = null;
+  /** Stores whether a legend is generated for the chart (Default: true). */
+  protected boolean legend = true;
+  /** Stores whether tooltips are generated for the chart data (Default: true). */
+  protected boolean tooltips = true;
+  /** Stores whether URLs are generated for the chart (Default: true). */
+  protected boolean urls = true;
   /** Holds the styles for the chart renderers. */
   protected Map<Integer,ChartRendererStyle> rendererStyle = new HashMap<Integer,ChartRendererStyle>();
   /** Holds the style for the chart's plot. */
   protected ChartPlotStyle plotStyle = null;
-
-  /**
+
+  /**
    * Creates a line style with default values.
-   * @param id a (unique) ID for the style
-   */
-  public AbstractChartStyle(String id) {
-    this( id, ChartType.LINE );
-  }
-
-  /**
-   * Creates a style with default values.
+   * @param id a (unique) ID for the style
+   */
+  public AbstractChartStyle(String id) {
+    this( id, ChartType.LINE );
+  }
+
+  /**
+   * Creates a style with default values.
    * @param id   a (unique) ID for the style
-   * @param type style type
-   */
-  public AbstractChartStyle(String id, ChartType type) {
-    this(id,type,null,null,null,true,true,true);
-  }
-
-  /**
-   * Creates a style.
+   * @param type style type
+   */
+  public AbstractChartStyle(String id, ChartType type) {
+    this(id,type,null,null,null,true,true,true);
+  }
+
+  /**
+   * Creates a style.
    * @param id       a (unique) ID for the style
-   * @param type     style type
-   * @param title    title for the chart
-   * @param xTitle   title for the chart's X-axis
-   * @param yTitle   title for the chart's Y-axis
-   * @param legend   flag whether a legend is generated
-   * @param tooltips flag whether toolstips are generated
-   * @param urls     flag whether URLs are generated
-   */
-  public AbstractChartStyle(String    id,     ChartType type,
-                            String    title,  String  xTitle,   String  yTitle,
-                            boolean   legend, boolean tooltips, boolean urls) {
+   * @param type     style type
+   * @param title    title for the chart
+   * @param xTitle   title for the chart's X-axis
+   * @param yTitle   title for the chart's Y-axis
+   * @param legend   flag whether a legend is generated
+   * @param tooltips flag whether toolstips are generated
+   * @param urls     flag whether URLs are generated
+   */
+  public AbstractChartStyle(String    id,     ChartType type,
+                            String    title,  String  xTitle,   String  yTitle,
+                            boolean   legend, boolean tooltips, boolean urls) {
     this.id = id;
-    setType(type);
-    setLegend(legend);
-    setTooltips(tooltips);
-    setURLs(urls);
+    setType(type);
+    setLegend(legend);
+    setTooltips(tooltips);
+    setURLs(urls);
     getTitleStyle().setLabel(title);
     if ( xTitle != null )
       setAxisStyle(DOMAIN_AXIS, new ChartAxisStyle(xTitle,Color.BLACK,0.0,0.0) );
     if ( yTitle != null )
       setAxisStyle(RANGE_AXIS, new ChartAxisStyle(yTitle,Color.BLACK,0.0,0.0) );
-  }
-
+  }
+
   /**
    * Returns the (unique) ID for the style.
    */
@@ -139,23 +168,23 @@
     return id;
   }
 
-  /**
-   * Returns the type of the chart style.
-   */
-  public ChartType getType() {
-    return type;
-  }
-
-  /**
-   * Sets the type of the chart style.
-   * @param type the chart type
-   * @see ChartStyle#ChartType
-   */
-  public void setType(ChartType type) {
-    this.type = type;
-  }
+  /**
+   * Returns the type of the chart style.
+   */
+  public ChartType getType() {
+    return type;
+  }
 
   /**
+   * Sets the type of the chart style.
+   * @param type the chart type
+   * @see ChartStyle#ChartType
+   */
+  public void setType(ChartType type) {
+    this.type = type;
+  }
+
+  /**
    * Returns the orientation of the chart.
    */
   public PlotOrientation getOrientation() {
@@ -176,7 +205,7 @@
   public ChartLabelStyle getTitleStyle() {
     return titleStyle;
   }
-  
+  
   /**
    * Sets the style of the charts title.
    * @param style the new style (if {@code null} the style is
@@ -233,49 +262,49 @@
     this.borderVisible = visible;
   }
 
-  /**
-   * Returns whether the chart is configured to generate a legend.
-   */
-  public boolean hasLegend() {
-    return legend;
-  }
-
-  /**
-   * Sets whether the chart is configured to generate a legend.
-   */
-  public void setLegend(boolean legend) {
-    this.legend = legend;
-  }
-
-  /**
-   * Returns whether the chart is configured to generate tooltips for the data.
-   */
-  public boolean hasTooltips() {
-    return tooltips;
-  }
-
-  /**
-   * Sets whether the chart is configured to generate tooltips for the data.
-   */
-  public void setTooltips(boolean tooltips) {
-    this.tooltips = tooltips;
-  }
-
-  /**
-   * Returns whether the chart is configured to generate URLs.
-   */
-  public boolean hasURLs() {
-    return urls;
-  }
-
-  /**
-   * Sets whether the chart is configured to generate URLs.
-   */
-  public void setURLs(boolean urls) {
-    this.urls = urls;
-  }
+  /**
+   * Returns whether the chart is configured to generate a legend.
+   */
+  public boolean hasLegend() {
+    return legend;
+  }
 
   /**
+   * Sets whether the chart is configured to generate a legend.
+   */
+  public void setLegend(boolean legend) {
+    this.legend = legend;
+  }
+
+  /**
+   * Returns whether the chart is configured to generate tooltips for the data.
+   */
+  public boolean hasTooltips() {
+    return tooltips;
+  }
+
+  /**
+   * Sets whether the chart is configured to generate tooltips for the data.
+   */
+  public void setTooltips(boolean tooltips) {
+    this.tooltips = tooltips;
+  }
+
+  /**
+   * Returns whether the chart is configured to generate URLs.
+   */
+  public boolean hasURLs() {
+    return urls;
+  }
+
+  /**
+   * Sets whether the chart is configured to generate URLs.
+   */
+  public void setURLs(boolean urls) {
+    this.urls = urls;
+  }
+
+  /**
    * Returns the axis count.
    */
   public int getAxisCount() {
@@ -411,4 +440,4 @@
       else
         LOGGER.warn("Style contains no style definition for axis "+i);
   }
-}
+}

Modified: trunk/src/schmitzm/jfree/chart/style/BasicChartStyle.java
===================================================================
--- trunk/src/schmitzm/jfree/chart/style/BasicChartStyle.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/chart/style/BasicChartStyle.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,3 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 /*
  *  SDSS Framework - This file is part of the Spatial Decision Support System Framework Platform
  *
@@ -8,8 +37,8 @@
  *  Contact Information:                    info at andreas-enders.de
  */
 
-package schmitzm.jfree.chart.style;
-
+package schmitzm.jfree.chart.style;
+
 import org.jfree.chart.ChartFactory;
 import org.jfree.chart.JFreeChart;
 import org.jfree.chart.plot.CategoryPlot;
@@ -34,69 +63,69 @@
 
 import schmitzm.jfree.JFreeChartUtil;
 import schmitzm.lang.LangUtil;
-
-/**
- * This class provides a basis chart style for line, area an bar charts.
- * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
- * @version 1.0
- */
+
+/**
+ * This class provides a basis chart style for line, area an bar charts.
+ * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
+ * @version 1.0
+ */
 public class BasicChartStyle extends AbstractChartStyle {
-  /** Stores whether the chart is stacked. Line charts can never be stacked. */
-  protected boolean stacked = false;
-  /** Stores whether the chart is stepped. Bar charts are always stepped. */
-  protected boolean stepped = false;
-
-  /**
-   * Creates a normal line style with default values.
+  /** Stores whether the chart is stacked. Line charts can never be stacked. */
+  protected boolean stacked = false;
+  /** Stores whether the chart is stepped. Bar charts are always stepped. */
+  protected boolean stepped = false;
+
+  /**
+   * Creates a normal line style with default values.
    * @param id   a (unique) ID for the style
-   */
-  public BasicChartStyle(String id) {
-    this(id, ChartType.LINE);
-  }
-
-  /**
-   * Creates a normal, vertical line, bar or area style.
+   */
+  public BasicChartStyle(String id) {
+    this(id, ChartType.LINE);
+  }
+
+  /**
+   * Creates a normal, vertical line, bar or area style.
    * @param id   a (unique) ID for the style
-   * @param type type of the chart layout
-   */
-  public BasicChartStyle(String id, ChartType type) {
-    this(id, type, false, false, PlotOrientation.VERTICAL);
-  }
-
-  /**
-   * Creates a line, area or bar chart style.
+   * @param type type of the chart layout
+   */
+  public BasicChartStyle(String id, ChartType type) {
+    this(id, type, false, false, PlotOrientation.VERTICAL);
+  }
+
+  /**
+   * Creates a line, area or bar chart style.
    * @param id          a (unique) ID for the style
-   * @param type        style type
-   * @param stacked     flag whether the chart is stacked (ignored for line charts)
-   * @param stepped     flag whether the chart is stepped (ignored for bar charts)
-   * @param orientation orientation of the chart ({@link PlotOrientation.VERTICAL} or {@link PlotOrientation.HORIZONTAL})
-   */
-  public BasicChartStyle(String id, ChartType type, boolean stacked, boolean stepped, PlotOrientation orientation) {
-    this(id, type, stacked, stepped, orientation, null, null, null, true, true, true);
-  }
-
-  /**
-   * Creates a chart style.
+   * @param type        style type
+   * @param stacked     flag whether the chart is stacked (ignored for line charts)
+   * @param stepped     flag whether the chart is stepped (ignored for bar charts)
+   * @param orientation orientation of the chart ({@link PlotOrientation.VERTICAL} or {@link PlotOrientation.HORIZONTAL})
+   */
+  public BasicChartStyle(String id, ChartType type, boolean stacked, boolean stepped, PlotOrientation orientation) {
+    this(id, type, stacked, stepped, orientation, null, null, null, true, true, true);
+  }
+
+  /**
+   * Creates a chart style.
    * @param id       a (unique) ID for the style
-   * @param type     style type
-   * @param stacked  flag whether the chart is stacked (ignored for line charts)
-   * @param stepped  flag whether the chart is stepped (ignored for bar charts)
-   * @param orientation orientation of the chart ({@link PlotOrientation.VERTICAL} or {@link PlotOrientation.HORIZONTAL})
-   * @param title    title for the chart
-   * @param xTitle   title for the chart's X-axis
-   * @param yTitle   title for the chart's Y-axis
-   * @param legend   flag whether a legend is generated
-   * @param tooltips flag whether toolstips are generated
-   * @param urls     flag whether URLs are generated
-   */
-  public BasicChartStyle(String id, ChartType type, boolean stacked, boolean stepped,
-                         PlotOrientation orientation,
-                         String title,   String xTitle,    String yTitle,
-                         boolean legend, boolean tooltips, boolean urls) {
-    super(id, type, title, xTitle, yTitle, legend, tooltips, urls);
-    setStacked( stacked );
-    setStepped( stepped );
-    setOrientation( orientation );
+   * @param type     style type
+   * @param stacked  flag whether the chart is stacked (ignored for line charts)
+   * @param stepped  flag whether the chart is stepped (ignored for bar charts)
+   * @param orientation orientation of the chart ({@link PlotOrientation.VERTICAL} or {@link PlotOrientation.HORIZONTAL})
+   * @param title    title for the chart
+   * @param xTitle   title for the chart's X-axis
+   * @param yTitle   title for the chart's Y-axis
+   * @param legend   flag whether a legend is generated
+   * @param tooltips flag whether toolstips are generated
+   * @param urls     flag whether URLs are generated
+   */
+  public BasicChartStyle(String id, ChartType type, boolean stacked, boolean stepped,
+                         PlotOrientation orientation,
+                         String title,   String xTitle,    String yTitle,
+                         boolean legend, boolean tooltips, boolean urls) {
+    super(id, type, title, xTitle, yTitle, legend, tooltips, urls);
+    setStacked( stacked );
+    setStepped( stepped );
+    setOrientation( orientation );
   }
 
   /**
@@ -104,100 +133,100 @@
    */
   protected void throwUnsupportedTypeException() {
     throw new IllegalArgumentException("Only ChartType.LINE, ChartType.AREA or ChartType.BAR allowed for "+LangUtil.getSimpleClassName(this)+"!");
-  }
-
-  /**
-   * Sets the type of the chart style.
-   * @param type the chart type
-   * @exception IllegalArgumentException if {@link aType} is not of
-   *            {@link ChartType#LINE}, {@link ChartType#AREA} or
-   *            {@link ChartType#BAR}
-   */
+  }
+
+  /**
+   * Sets the type of the chart style.
+   * @param type the chart type
+   * @exception IllegalArgumentException if {@link aType} is not of
+   *            {@link ChartType#LINE}, {@link ChartType#AREA} or
+   *            {@link ChartType#BAR}
+   */
   public void setType(ChartType type) {
-    super.setType(type);
-    switch( type ) {
-      // supported types
-      case LINE: stacked = false;
-                 break;
-      case BAR:  stepped = true;
-                 break;
-      case AREA: break;
-      // unsupported types
-      default: throwUnsupportedTypeException();
-    }
-    super.setType(type);
+    super.setType(type);
+    switch( type ) {
+      // supported types
+      case LINE: stacked = false;
+                 break;
+      case BAR:  stepped = true;
+                 break;
+      case AREA: break;
+      // unsupported types
+      default: throwUnsupportedTypeException();
+    }
+    super.setType(type);
   }
-  
-  /**
-   * Returns whether the chart is stacked.
-   * @return {@code false} for line charts
-   */
-  public boolean isStacked() {
-    return stacked;
-  }
-
-  /**
-   * Sets whether the chart is stacked. Sets the {@link #stacked} property
-   * to {@code false} for line charts, even {@code aStacked} is {@code true}.
-   */
-  public void setStacked(boolean stacked) {
-    if ( type == ChartType.LINE && stacked ) {
-      LOGGER.warn("Stacked property can not be enabled for line charts! Command ignored...");
-      stacked = false;
-    }
-    this.stacked = stacked;
-
-    if ( type == ChartType.AREA && stepped && stacked ) {
-      LOGGER.warn("Area chart style can not be stepped and stacked at the same time. Stepped property automatically disabled...");
-      stepped = false;
-    }
-  }
-
-  /**
-   * Returns whether the chart is stepped.
-   * @return {@code true} for bar charts
-   */
-  public boolean isStepped() {
-    return stepped;
-  }
-
-  /**
-   * Sets whether the chart is stepped. Sets the {@link #stepped} property
-   * to {@code true} for bar charts, even {@code stepped} is {@code false}.
-   */
-  public void setStepped(boolean stepped) {
-    if ( type == ChartType.BAR && !stepped) {
-      LOGGER.warn("Stepped property can not be disabled for bar charts. Command ignored...");
-      stepped = true;
-    }
-    this.stepped = stepped;
-
-    if ( type == ChartType.AREA && stacked && stepped ) {
-      LOGGER.warn("Area chart style can not be stepped and stacked at the same time. Stacked property automatically disabled...");
-      stacked = false;
-    }
-  }
-
-  /**
-   * Creates a chart for the given {@link Dataset} and applies the style.
-   * @param dataset the data for the chart
-   * @exception UnsupportedOperationException if the style can not be applied
-   *            to the given dataset
-   */
-  public JFreeChart applyToDataset(Dataset dataset) {
-    JFreeChart chart = null;
-    switch ( type ) {
-      case LINE: chart = createLineChart(dataset);
-                 break;
-      case AREA: chart = createAreaChart(dataset);
-                 break;
-      case BAR:  chart = createBarChart(dataset);
-                 break;
+  
+  /**
+   * Returns whether the chart is stacked.
+   * @return {@code false} for line charts
+   */
+  public boolean isStacked() {
+    return stacked;
+  }
+
+  /**
+   * Sets whether the chart is stacked. Sets the {@link #stacked} property
+   * to {@code false} for line charts, even {@code aStacked} is {@code true}.
+   */
+  public void setStacked(boolean stacked) {
+    if ( type == ChartType.LINE && stacked ) {
+      LOGGER.warn("Stacked property can not be enabled for line charts! Command ignored...");
+      stacked = false;
+    }
+    this.stacked = stacked;
+
+    if ( type == ChartType.AREA && stepped && stacked ) {
+      LOGGER.warn("Area chart style can not be stepped and stacked at the same time. Stepped property automatically disabled...");
+      stepped = false;
+    }
+  }
+
+  /**
+   * Returns whether the chart is stepped.
+   * @return {@code true} for bar charts
+   */
+  public boolean isStepped() {
+    return stepped;
+  }
+
+  /**
+   * Sets whether the chart is stepped. Sets the {@link #stepped} property
+   * to {@code true} for bar charts, even {@code stepped} is {@code false}.
+   */
+  public void setStepped(boolean stepped) {
+    if ( type == ChartType.BAR && !stepped) {
+      LOGGER.warn("Stepped property can not be disabled for bar charts. Command ignored...");
+      stepped = true;
+    }
+    this.stepped = stepped;
+
+    if ( type == ChartType.AREA && stacked && stepped ) {
+      LOGGER.warn("Area chart style can not be stepped and stacked at the same time. Stacked property automatically disabled...");
+      stacked = false;
+    }
+  }
+
+  /**
+   * Creates a chart for the given {@link Dataset} and applies the style.
+   * @param dataset the data for the chart
+   * @exception UnsupportedOperationException if the style can not be applied
+   *            to the given dataset
+   */
+  public JFreeChart applyToDataset(Dataset dataset) {
+    JFreeChart chart = null;
+    switch ( type ) {
+      case LINE: chart = createLineChart(dataset);
+                 break;
+      case AREA: chart = createAreaChart(dataset);
+                 break;
+      case BAR:  chart = createBarChart(dataset);
+                 break;
       // unsupported types
       default: throwUnsupportedTypeException();
     }
-    applyToChart(chart);
-    return chart;
+    applyToChart(chart);
+    return chart;
   }
   
   /**
@@ -215,139 +244,139 @@
       LOGGER.warn("Properties of BasicChartStyle can not be applied to plot: "+chart.getPlot());
   }
   
-
-  /**
-   * Creates a line chart from an {@link XYDataset} or {@link CategoryDataset}
-   * @param dataset Dataset
-   */
-  private JFreeChart createLineChart(Dataset dataset) {
-    JFreeChart chart = null;
-    // XYDataset -> XYLineChart
-    if (dataset instanceof XYDataset) {
-      chart = ChartFactory.createXYLineChart(
+
+  /**
+   * Creates a line chart from an {@link XYDataset} or {@link CategoryDataset}
+   * @param dataset Dataset
+   */
+  private JFreeChart createLineChart(Dataset dataset) {
+    JFreeChart chart = null;
+    // XYDataset -> XYLineChart
+    if (dataset instanceof XYDataset) {
+      chart = ChartFactory.createXYLineChart(
           getTitleStyle().getLabel(),
           getAxisStyle(DOMAIN_AXIS).getLabel(),
           getAxisStyle(RANGE_AXIS).getLabel(),
-          (XYDataset)dataset,
-          orientation,
-          legend,
-          tooltips,
-          urls
-      );
+          (XYDataset)dataset,
+          orientation,
+          legend,
+          tooltips,
+          urls
+      );
 //      if ( stepped )
-//        chart.getXYPlot().setRenderer( new XYStepRenderer() );
-    }
-    // CategoryDataset -> LineChart
-    if (dataset instanceof CategoryDataset) {
-      chart = ChartFactory.createLineChart(
+//        chart.getXYPlot().setRenderer( new XYStepRenderer() );
+    }
+    // CategoryDataset -> LineChart
+    if (dataset instanceof CategoryDataset) {
+      chart = ChartFactory.createLineChart(
           getTitleStyle().getLabel(),
           getAxisStyle(DOMAIN_AXIS).getLabel(),
           getAxisStyle(RANGE_AXIS).getLabel(),
-          (CategoryDataset)dataset,
-          orientation,
-          legend,
-          tooltips,
-          urls
-      );
-//      if ( stepped )
-//        chart.getCategoryPlot().setRenderer(  new CategoryStepRenderer() );
-    }
-    return chart;
-  }
-
-  /**
-   * Creates an area chart from an {@link XYDataset} or {@link CategoryDataset}
-   * @param dataset Dataset
-   */
-  private JFreeChart createAreaChart(Dataset dataset) {
-    JFreeChart chart = null;
-    // XYDataset -> XYAreaChart
-    if (dataset instanceof XYDataset) {
-      chart = ChartFactory.createXYAreaChart(
-          getTitleStyle().getLabel(),
-          getAxisStyle(DOMAIN_AXIS).getLabel(),
-          getAxisStyle(RANGE_AXIS).getLabel(),
-          (XYDataset) dataset,
-          orientation,
-          legend,
-          tooltips,
-          urls
-          );
-//      if (stacked) {
-//        if (dataset instanceof TableXYDataset)
-//          chart.getXYPlot().setRenderer(new StackedXYAreaRenderer2());
-//        else
-//          throw new UnsupportedOperationException("Chart creation: Stacked area charts can not be applied on XYDataset. TableXYDataset needed!");
-//        if (stepped)
-//          throw new UnsupportedOperationException("Chart creation: A stacked area chart can not be stepped the same time. Use a stacked bar chart instead!");
-//      } else  {
-//        if (stepped)
-//          chart.getXYPlot().setRenderer(new XYStepAreaRenderer(XYStepAreaRenderer.AREA));
-//      }
-    }
-    // CategoryDataset -> AreaChart
-    if (dataset instanceof CategoryDataset) {
-      chart = ChartFactory.createAreaChart(
+          (CategoryDataset)dataset,
+          orientation,
+          legend,
+          tooltips,
+          urls
+      );
+//      if ( stepped )
+//        chart.getCategoryPlot().setRenderer(  new CategoryStepRenderer() );
+    }
+    return chart;
+  }
+
+  /**
+   * Creates an area chart from an {@link XYDataset} or {@link CategoryDataset}
+   * @param dataset Dataset
+   */
+  private JFreeChart createAreaChart(Dataset dataset) {
+    JFreeChart chart = null;
+    // XYDataset -> XYAreaChart
+    if (dataset instanceof XYDataset) {
+      chart = ChartFactory.createXYAreaChart(
           getTitleStyle().getLabel(),
           getAxisStyle(DOMAIN_AXIS).getLabel(),
           getAxisStyle(RANGE_AXIS).getLabel(),
-          (CategoryDataset)dataset,
-          orientation,
-          legend,
-          tooltips,
-          urls
-      );
-//      if ( stepped )
-//        throw new UnsupportedOperationException("Chart creation: Stepped area style can not be applied on CategoryDataset. Use a bar chart instead!");
-//      if ( stacked )
-//        chart.getCategoryPlot().setRenderer(  new StackedAreaRenderer(false) );
-    }
-
-    return chart;
-  }
-
-  /**
-   * Creates a bar chart from an {@link XYDataset} or {@link CategoryDataset}
-   * @param dataset Dataset
-   */
-  private JFreeChart createBarChart(Dataset dataset) {
-    JFreeChart chart = null;
-    // XYDataset -> XYBarChart
-    if (dataset instanceof XYDataset) {
-      chart = ChartFactory.createXYBarChart(
+          (XYDataset) dataset,
+          orientation,
+          legend,
+          tooltips,
+          urls
+          );
+//      if (stacked) {
+//        if (dataset instanceof TableXYDataset)
+//          chart.getXYPlot().setRenderer(new StackedXYAreaRenderer2());
+//        else
+//          throw new UnsupportedOperationException("Chart creation: Stacked area charts can not be applied on XYDataset. TableXYDataset needed!");
+//        if (stepped)
+//          throw new UnsupportedOperationException("Chart creation: A stacked area chart can not be stepped the same time. Use a stacked bar chart instead!");
+//      } else  {
+//        if (stepped)
+//          chart.getXYPlot().setRenderer(new XYStepAreaRenderer(XYStepAreaRenderer.AREA));
+//      }
+    }
+    // CategoryDataset -> AreaChart
+    if (dataset instanceof CategoryDataset) {
+      chart = ChartFactory.createAreaChart(
           getTitleStyle().getLabel(),
           getAxisStyle(DOMAIN_AXIS).getLabel(),
+          getAxisStyle(RANGE_AXIS).getLabel(),
+          (CategoryDataset)dataset,
+          orientation,
+          legend,
+          tooltips,
+          urls
+      );
+//      if ( stepped )
+//        throw new UnsupportedOperationException("Chart creation: Stepped area style can not be applied on CategoryDataset. Use a bar chart instead!");
+//      if ( stacked )
+//        chart.getCategoryPlot().setRenderer(  new StackedAreaRenderer(false) );
+    }
+
+    return chart;
+  }
+
+  /**
+   * Creates a bar chart from an {@link XYDataset} or {@link CategoryDataset}
+   * @param dataset Dataset
+   */
+  private JFreeChart createBarChart(Dataset dataset) {
+    JFreeChart chart = null;
+    // XYDataset -> XYBarChart
+    if (dataset instanceof XYDataset) {
+      chart = ChartFactory.createXYBarChart(
+          getTitleStyle().getLabel(),
+          getAxisStyle(DOMAIN_AXIS).getLabel(),
           false,
           getAxisStyle(RANGE_AXIS).getLabel(),
-          (IntervalXYDataset)(dataset instanceof TableXYDataset ? (TableXYDataset)dataset : new XYBarDataset( (XYDataset) dataset, 0.5d)),
-          PlotOrientation.VERTICAL,
-          true,
-          true,
-          true
-      );
-//      if ( stacked ) {
-//        if ( dataset instanceof TableXYDataset )
-//          chart.getXYPlot().setRenderer(new StackedXYBarRenderer());
-//        else
-//          throw new UnsupportedOperationException("Chart creation: Stacked bar charts can not be applied on XYDataset. TableXYDataset needed!");
-//      }
-    }
-    // CategoryDataset -> BarChart
-    if (dataset instanceof CategoryDataset) {
-      chart = ChartFactory.createBarChart(
+          (IntervalXYDataset)(dataset instanceof TableXYDataset ? (TableXYDataset)dataset : new XYBarDataset( (XYDataset) dataset, 0.5d)),
+          PlotOrientation.VERTICAL,
+          true,
+          true,
+          true
+      );
+//      if ( stacked ) {
+//        if ( dataset instanceof TableXYDataset )
+//          chart.getXYPlot().setRenderer(new StackedXYBarRenderer());
+//        else
+//          throw new UnsupportedOperationException("Chart creation: Stacked bar charts can not be applied on XYDataset. TableXYDataset needed!");
+//      }
+    }
+    // CategoryDataset -> BarChart
+    if (dataset instanceof CategoryDataset) {
+      chart = ChartFactory.createBarChart(
           getTitleStyle().getLabel(),
           getAxisStyle(DOMAIN_AXIS).getLabel(),
           getAxisStyle(RANGE_AXIS).getLabel(),
-          (CategoryDataset)dataset,
-          orientation,
-          legend,
-          tooltips,
-          urls
-      );
-//      if ( stacked )
-//        chart.getCategoryPlot().setRenderer(  new StackedBarRenderer(false) );
-    }
-
-    return chart;
-  }
-}
+          (CategoryDataset)dataset,
+          orientation,
+          legend,
+          tooltips,
+          urls
+      );
+//      if ( stacked )
+//        chart.getCategoryPlot().setRenderer(  new StackedBarRenderer(false) );
+    }
+
+    return chart;
+  }
+}

Modified: trunk/src/schmitzm/jfree/chart/style/ChartAxisStyle.java
===================================================================
--- trunk/src/schmitzm/jfree/chart/style/ChartAxisStyle.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/chart/style/ChartAxisStyle.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,16 +1,34 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.jfree.chart.style;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.jfree.chart.style;
-
 import java.awt.Color;
 import java.awt.Paint;
 import java.text.DateFormat;
@@ -25,13 +43,13 @@
 
 import schmitzm.lang.LangUtil;
 import skrueger.i8n.Translation;
-
-/**
- * This class is defines the design style of a chart {@link Axis}.
- * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
- * @version 1.0
- */
-public class ChartAxisStyle extends ChartLabelStyle {
+
+/**
+ * This class is defines the design style of a chart {@link Axis}.
+ * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
+ * @version 1.0
+ */
+public class ChartAxisStyle extends ChartLabelStyle {
   /** Holds the angle (in degrees) the label is rotated by. */
   protected Double angleDegr = 0.0;
   /** Holds the angle (in degrees) the axis values are rotated by. */
@@ -237,4 +255,4 @@
       // Give a warn if another angle should be applied to DateAxis
       LOGGER.warn("Only 0 or 90 degrees (horizontal/vertical) can be applied to values of "+LangUtil.getSimpleClassName(axis)+": "+angle);
   }
-}
+}

Modified: trunk/src/schmitzm/jfree/chart/style/ChartLabelStyle.java
===================================================================
--- trunk/src/schmitzm/jfree/chart/style/ChartLabelStyle.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/chart/style/ChartLabelStyle.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,16 +1,34 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.jfree.chart.style;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.jfree.chart.style;
-
 import java.awt.Color;
 import java.awt.Paint;
 import java.util.Locale;
@@ -19,16 +37,16 @@
 
 import schmitzm.lang.LangUtil;
 import skrueger.i8n.Translation;
-
-/**
+
+/**
  * This class is a general super class for a design style of text displayed
  * in a chart. This can be an localized text according to {@link Translation} or
  * a simple (unlocalized) String. The {@link #setLabel(String)} method will
  * try to decode the string for multiple languages. If this is not possible
  * the core string is taken as label.
- * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
- * @version 1.0
- */
+ * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
+ * @version 1.0
+ */
 public class ChartLabelStyle {
   /** Logger for this class */
   protected final Category LOGGER = LangUtil.createLogger(this);
@@ -110,4 +128,4 @@
     this.paint = color;
   }
   
-}
+}

Modified: trunk/src/schmitzm/jfree/chart/style/ChartPlotStyle.java
===================================================================
--- trunk/src/schmitzm/jfree/chart/style/ChartPlotStyle.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/chart/style/ChartPlotStyle.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,16 +1,34 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.jfree.chart.style;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.jfree.chart.style;
-
 import java.awt.Color;
 import java.awt.Insets;
 import java.awt.Paint;
@@ -38,8 +56,8 @@
 
 import schmitzm.jfree.JFreeChartUtil;
 import schmitzm.lang.LangUtil;
-
-/**
+
+/**
  * This class defines the rendering style the charts plot(s). The following
  * properties are available:
  * <ul>
@@ -50,14 +68,14 @@
  *       {@link CategoryPlot})</li>
  *   <li>range grid line visibility and color (only applicable for {@link XYPlot} and
  *       {@link CategoryPlot})</li>
- * </ul>
- * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
- * @version 1.0
- */
+ * </ul>
+ * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
+ * @version 1.0
+ */
 public class ChartPlotStyle {
   /** Logger for this class */
   protected final Category LOGGER = LangUtil.createLogger(this);
-
+
   /** Holds the inner margins of the plot. */
   protected RectangleInsets insets = null;;
   /** Holds the foreground transparency. */
@@ -281,4 +299,4 @@
     if ( getRangeGridlinePaint() != null )
       plot.setRangeGridlinePaint( getRangeGridlinePaint() );
   }
-}
+}

Modified: trunk/src/schmitzm/jfree/chart/style/ChartRendererStyle.java
===================================================================
--- trunk/src/schmitzm/jfree/chart/style/ChartRendererStyle.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/chart/style/ChartRendererStyle.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,16 +1,34 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.jfree.chart.style;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.jfree.chart.style;
-
 import java.awt.Color;
 import java.awt.Paint;
 import java.text.DateFormat;
@@ -35,8 +53,8 @@
 
 import schmitzm.jfree.JFreeChartUtil;
 import schmitzm.lang.LangUtil;
-
-/**
+
+/**
  * This class defines the rendering style the charts series. The following
  * properties are available:
  * <ul>
@@ -45,14 +63,14 @@
  *   <li>visibility of series shapes</li>
  *   <li>percentage margin between bars (only applicable for {@link XYBarRenderer})</li>
  * </ul>
-
- * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
- * @version 1.0
- */
+
+ * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
+ * @version 1.0
+ */
 public class ChartRendererStyle {
   /** Logger for this class */
   protected final Category LOGGER = LangUtil.createLogger(this);
-
+
   /** Holds whether the item labels are visible for a series. */
   protected Map<Integer, Boolean> seriesItemLabelsVisible = new HashMap<Integer, Boolean>();
   /** Holds the color a series is painted with. */
@@ -198,4 +216,4 @@
     if ( getMargin() != null )
       renderer.setMargin(margin);
   }
-}
+}

Modified: trunk/src/schmitzm/jfree/chart/style/ChartStyle.java
===================================================================
--- trunk/src/schmitzm/jfree/chart/style/ChartStyle.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/chart/style/ChartStyle.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,16 +1,34 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.jfree.chart.style;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.jfree.chart.style;
-
 import java.awt.Color;
 import java.awt.Paint;
 
@@ -20,19 +38,19 @@
 import org.jfree.chart.plot.PlotOrientation;
 import org.jfree.data.general.Dataset;
 
-
-/**
- * This interface is a general super class for a design style of a {@link JFreeChart}.
- * Sub classes should read the style from an xml element or something like that.
- * Maybe there could be a general implementation representing a style for
- * basic charts (bar, line and area charts) and special implementations for
- * special chart types (e.g. financial, statistical oder spider charts).
- * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
- * @version 1.0
- */
+
+/**
+ * This interface is a general super class for a design style of a {@link JFreeChart}.
+ * Sub classes should read the style from an xml element or something like that.
+ * Maybe there could be a general implementation representing a style for
+ * basic charts (bar, line and area charts) and special implementations for
+ * special chart types (e.g. financial, statistical oder spider charts).
+ * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
+ * @version 1.0
+ */
 public interface ChartStyle {
   final static Logger LOGGER = Logger.getLogger(ChartStyle.class);
-  
+  
   /** Constant for the domain axis (X). */
   public static final int DOMAIN_AXIS = 0;
   /** Constant for the domain axis (X). Synonym for {@link #DOMAIN_AXIS}.*/
@@ -44,21 +62,21 @@
   /** Constant for the range axis (Y). Synonym for {@link #RANGE_AXIS}. */
   public static final int Y_AXIS_LEFT  = RANGE_AXIS;
   /** Constant for the second range axis (Y). */
-  public static final int RANGE_AXIS2 = 2;
+  public static final int RANGE_AXIS2 = 2;
   /** Constant for the second range axis (Y). Synonym for {@link #RANGE_AXIS2}. */
-  public static final int Y_AXIS2 = RANGE_AXIS2;
+  public static final int Y_AXIS2 = RANGE_AXIS2;
   /** Constant for the second range axis (Y). Synonym for {@link #RANGE_AXIS2}. */
-  public static final int Y_AXIS_RIGHT = RANGE_AXIS2;
-
+  public static final int Y_AXIS_RIGHT = RANGE_AXIS2;
+
   /**
    * Returns an (unique) ID for the style.
    */
   public String getID();
 
-  /**
-   * Returns the type of the chart style.
-   */
-  public ChartType getType();
+  /**
+   * Returns the type of the chart style.
+   */
+  public ChartType getType();
 
   /**
    * Returns the orientation of the chart.
@@ -72,7 +90,7 @@
    * @param orientation the orientation of the chart
    */
   public void setOrientation(PlotOrientation orientation);
-
+
   /**
    * Returns the style of the chart title. <b>Should never return
    * {@code null}!!</b>
@@ -117,32 +135,32 @@
    */
   public void setBorderVisible(boolean visible);
   
-  /**
-   * Returns whether the chart is configured to generate a legend.
-   */
-  public boolean hasLegend();
+  /**
+   * Returns whether the chart is configured to generate a legend.
+   */
+  public boolean hasLegend();
 
   /**
    * Sets whether the chart is configured to generate a legend.
    */
   public void setLegend(boolean legend);
-
-  /**
-   * Returns whether the chart is configured to generate tooltips for the data.
-   */
-  public boolean hasTooltips();
 
   /**
+   * Returns whether the chart is configured to generate tooltips for the data.
+   */
+  public boolean hasTooltips();
+
+  /**
    * Sets whether the chart is configured to generate tooltips for the data.
    */
   public void setTooltips(boolean tooltips);
-
-  /**
-   * Returns whether the chart is configured to generate URLs.
-   */
-  public boolean hasURLs();
 
   /**
+   * Returns whether the chart is configured to generate URLs.
+   */
+  public boolean hasURLs();
+
+  /**
    * Sets whether the chart is configured to generate URLs.
    */
   public void setURLs(boolean urls);
@@ -202,13 +220,13 @@
    */
   public void applyToChart(JFreeChart chart);
 
-  /**
-   * Generates a chart using the given data and the style represented by
-   * this class.
-   * @param dataset the data for the chart
-   * @exception UnsupportedOperationException if the style can not be applied
-   *            to the given dataset
-   */
+  /**
+   * Generates a chart using the given data and the style represented by
+   * this class.
+   * @param dataset the data for the chart
+   * @exception UnsupportedOperationException if the style can not be applied
+   *            to the given dataset
+   */
   public JFreeChart applyToDataset(Dataset dataset);
 
-}
+}

Modified: trunk/src/schmitzm/jfree/chart/style/ChartStyleUtil.java
===================================================================
--- trunk/src/schmitzm/jfree/chart/style/ChartStyleUtil.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/chart/style/ChartStyleUtil.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,14 +1,32 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package schmitzm.jfree.chart.style;
 
 import java.io.File;

Modified: trunk/src/schmitzm/jfree/chart/style/ChartStyleXMLFactory.java
===================================================================
--- trunk/src/schmitzm/jfree/chart/style/ChartStyleXMLFactory.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/chart/style/ChartStyleXMLFactory.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,16 +1,34 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.jfree.chart.style;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.jfree.chart.style;
-
 import java.awt.Color;
 import java.awt.Paint;
 import java.io.File;
@@ -32,11 +50,11 @@
 
 import schmitzm.xml.XMLUtil;
 
-/**
- * This class defines a factory to create a chart style from XML.
- * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
- * @version 1.0
- */
+/**
+ * This class defines a factory to create a chart style from XML.
+ * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
+ * @version 1.0
+ */
 public class ChartStyleXMLFactory<E extends ChartStyle> {
   /** URL for XML schema */
   public static final String SCHEMA_URI = "http://www.wikisquare.de/AtlasML";
@@ -242,7 +260,7 @@
     
     return style;
   }
-  
+  
   /**
    * Creates a {@link ChartRendererStyle} from XML element.
    * @param element an element
@@ -500,4 +518,4 @@
     return axisElem;
   }
 
-}
+}

Modified: trunk/src/schmitzm/jfree/chart/style/ChartType.java
===================================================================
--- trunk/src/schmitzm/jfree/chart/style/ChartType.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/chart/style/ChartType.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,3 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package schmitzm.jfree.chart.style;
 
 import java.awt.image.BufferedImage;
@@ -87,4 +116,4 @@
 			return toString();
 		return resource;
 	}
-};
\ No newline at end of file
+};

Modified: trunk/src/schmitzm/jfree/chart/style/ScatterChartStyle.java
===================================================================
--- trunk/src/schmitzm/jfree/chart/style/ScatterChartStyle.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/chart/style/ScatterChartStyle.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,111 +1,129 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.jfree.chart.style;
-
-import java.awt.Color;
-
-import org.jfree.chart.JFreeChart;
-import org.jfree.chart.renderer.xy.XYItemRenderer;
-import org.jfree.data.general.Dataset;
-import org.jfree.data.xy.XYDataset;
-import org.jfree.data.xy.XYSeriesCollection;
-
-import schmitzm.jfree.JFreeChartUtil;
-import schmitzm.lang.LangUtil;
-
-/**
- * This class provides a chart style for scatter chart, which shows the data as
- * points. Besides the points it is possible to show a regression line ("line of best
- * fit") for the data points.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- */
-public class ScatterChartStyle extends AbstractChartStyle {
-  /** Stores whether a regression line ("line of best fit") for the
-   *  data points is shown. */
-  protected boolean regrLineVisible = true;
-
-  /**
-   * Creates a scatter chart style a regression line shown.
-   * @param id   a (unique) ID for the style
-   */
-  public ScatterChartStyle(String id) {
-    super(id, ChartType.SCATTER);
-  }
-  
-  /**
-   * Returns whether a regression line is shown.
-   */
-  public boolean isRegressionLineVisible() {
-    return regrLineVisible;
-  }
-  
-  /**
-   * Sets whether a regression line is shown.
-   */
-  public void setRegressionLineVisible(boolean visible) {
-    this.regrLineVisible = visible;
-  }
-  
-
-  /**
-   * Creates a scatter chart for the given {@link Dataset} and applies the style.
-   * @param dataset the data for the chart
-   * @exception UnsupportedOperationException if the style can not be applied
-   *            to the given dataset
-   */
-  @Override
-  public JFreeChart applyToDataset(Dataset dataset) {
-    if ( !(dataset instanceof XYDataset) )
-      throw new UnsupportedOperationException("ScatterChartStyle can only be applied to XYDataset: "+LangUtil.getSimpleClassName(dataset));
-
-    // create default scatter chart
-    JFreeChart chart = JFreeChartUtil.createRegressionChart(
-        (XYDataset)dataset, "", "", "", isRegressionLineVisible()
-    );
-    
-    // apply style
-    applyToChart(chart);
-    return chart;
-  }
-
-  /**
-   * Applies the style to an existing chart.
-   * @param chart chart the style is applied to
-   * @exception UnsupportedOperationException if the style can not be applied
-   *            to the given dataset
-   */
-  public void applyToChart(JFreeChart chart) {
-    if ( chart.getXYPlot() == null )
-      throw new UnsupportedOperationException("ScatterChartStyle can only be applied to XYPlot: "+LangUtil.getSimpleClassName(chart.getPlot()));
-
-    // Create regression line if not already existing
-    if ( isRegressionLineVisible() && chart.getXYPlot().getRendererCount() < 2 ) {
-      // Create sample data for regression line for primary dataset (primary series)
-      // -> plot function directly is not yet available in JFreeChart
-      XYSeriesCollection dataset         = (XYSeriesCollection)chart.getXYPlot().getDataset();
-      String             regressionTitle = getTitleStyle().getLabel() + " (RegressionLine)";
-      XYDataset          regressionData  = JFreeChartUtil.createRegressionLineDataset(
-                                                 dataset, 0, regressionTitle, 2);
-      // Add regression line to plot (with default color)
-      JFreeChartUtil.addRegressionLineToPlot(chart.getXYPlot(), regressionData, Color.blue);
-    }
-
-    // apply "normal" style properties
-    super.applyToChart(chart);
-
-    // apply visiblity of regression line
-    XYItemRenderer regrLineRenderer = chart.getXYPlot().getRenderer(1);
-    if ( regrLineRenderer != null )
-      regrLineRenderer.setSeriesVisible(0, isRegressionLineVisible() );
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.jfree.chart.style;
+
+import java.awt.Color;
+
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.renderer.xy.XYItemRenderer;
+import org.jfree.data.general.Dataset;
+import org.jfree.data.xy.XYDataset;
+import org.jfree.data.xy.XYSeriesCollection;
+
+import schmitzm.jfree.JFreeChartUtil;
+import schmitzm.lang.LangUtil;
+
+/**
+ * This class provides a chart style for scatter chart, which shows the data as
+ * points. Besides the points it is possible to show a regression line ("line of best
+ * fit") for the data points.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ */
+public class ScatterChartStyle extends AbstractChartStyle {
+  /** Stores whether a regression line ("line of best fit") for the
+   *  data points is shown. */
+  protected boolean regrLineVisible = true;
+
+  /**
+   * Creates a scatter chart style a regression line shown.
+   * @param id   a (unique) ID for the style
+   */
+  public ScatterChartStyle(String id) {
+    super(id, ChartType.SCATTER);
+  }
+  
+  /**
+   * Returns whether a regression line is shown.
+   */
+  public boolean isRegressionLineVisible() {
+    return regrLineVisible;
+  }
+  
+  /**
+   * Sets whether a regression line is shown.
+   */
+  public void setRegressionLineVisible(boolean visible) {
+    this.regrLineVisible = visible;
+  }
+  
+
+  /**
+   * Creates a scatter chart for the given {@link Dataset} and applies the style.
+   * @param dataset the data for the chart
+   * @exception UnsupportedOperationException if the style can not be applied
+   *            to the given dataset
+   */
+  @Override
+  public JFreeChart applyToDataset(Dataset dataset) {
+    if ( !(dataset instanceof XYDataset) )
+      throw new UnsupportedOperationException("ScatterChartStyle can only be applied to XYDataset: "+LangUtil.getSimpleClassName(dataset));
+
+    // create default scatter chart
+    JFreeChart chart = JFreeChartUtil.createRegressionChart(
+        (XYDataset)dataset, "", "", "", isRegressionLineVisible()
+    );
+    
+    // apply style
+    applyToChart(chart);
+    return chart;
+  }
+
+  /**
+   * Applies the style to an existing chart.
+   * @param chart chart the style is applied to
+   * @exception UnsupportedOperationException if the style can not be applied
+   *            to the given dataset
+   */
+  public void applyToChart(JFreeChart chart) {
+    if ( chart.getXYPlot() == null )
+      throw new UnsupportedOperationException("ScatterChartStyle can only be applied to XYPlot: "+LangUtil.getSimpleClassName(chart.getPlot()));
+
+    // Create regression line if not already existing
+    if ( isRegressionLineVisible() && chart.getXYPlot().getRendererCount() < 2 ) {
+      // Create sample data for regression line for primary dataset (primary series)
+      // -> plot function directly is not yet available in JFreeChart
+      XYSeriesCollection dataset         = (XYSeriesCollection)chart.getXYPlot().getDataset();
+      String             regressionTitle = getTitleStyle().getLabel() + " (RegressionLine)";
+      XYDataset          regressionData  = JFreeChartUtil.createRegressionLineDataset(
+                                                 dataset, 0, regressionTitle, 2);
+      // Add regression line to plot (with default color)
+      JFreeChartUtil.addRegressionLineToPlot(chart.getXYPlot(), regressionData, Color.blue);
+    }
+
+    // apply "normal" style properties
+    super.applyToChart(chart);
+
+    // apply visiblity of regression line
+    XYItemRenderer regrLineRenderer = chart.getXYPlot().getRenderer(1);
+    if ( regrLineRenderer != null )
+      regrLineRenderer.setSeriesVisible(0, isRegressionLineVisible() );
+  }
+
+}

Modified: trunk/src/schmitzm/jfree/feature/Feature2DatasetMapping.java
===================================================================
--- trunk/src/schmitzm/jfree/feature/Feature2DatasetMapping.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/feature/Feature2DatasetMapping.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,86 +1,104 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.jfree.feature;
-
-import org.geotools.feature.Feature;
-import org.geotools.feature.FeatureCollection;
-import org.jfree.data.general.Dataset;
-
-/**
- * This class implements the mapping between {@link Dataset} items (points in chart)
- * and the corresponding {@link Feature Features}.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- */
-public abstract class Feature2DatasetMapping<E, F extends Dataset> {
-  /** Holds the {@link FeatureCollection} for the mapping */
-  protected FeatureCollection featureCollection = null;
-
-  /** Holds the {@link Dataset} for the mapping */
-  protected F dataset = null;
-
-  /**
-   * Creates a mapping. 
-   * @param fc a {@link FeatureCollection} (can be {@code null}) 
-   */
-  public Feature2DatasetMapping(FeatureCollection fc, F dataset) {
-    this.featureCollection = fc;
-    this.dataset           = dataset;
-  }
-
-  /**
-   * Returns the {@link FeatureCollection} the mapping is provided for.
-   */
-  public FeatureCollection getFeatureCollection() {
-    return featureCollection;
-  }
-
-  /**
-   * Returns the {@link Dataset} the mapping is provided for.
-   */
-  public F getDataset() {
-    return dataset;
-  }
-
-  /**
-   * Sets the mapping between a feature ID and a dataset item.
-   * @param featureID    feature ID
-   * @param itemID       defines the dataset item
-   */
-  public abstract void setMapping(String featureID, E itemID);
-  
-  /**
-   * Removes the mapping of a feature ID.
-   * @param fID feature ID
-   */
-  public abstract void removeMappingForFeatureID(String fID);
-  
-  /**
-   * Removes the mapping for a dataset item.
-   * @param itemID    dataset item
-   */
-  public abstract void removeMappingForDataItem(E itemID);
-
-  /**
-   * Returns the data items for a given feature ID.
-   * @param fID a feature ID
-   * @return {@code null} if no data item is registered for the feature ID
-   */
-  public abstract E getDataID(String fID);
-  
-  /**
-   * Returns the feature ID for a given data item.
-   * @param itemID a data item
-   * @return {@code null} if no feature ID is registered for the data item
-   */
-  public abstract String getFeatureID(E itemID);
-  
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.jfree.feature;
+
+import org.geotools.feature.Feature;
+import org.geotools.feature.FeatureCollection;
+import org.jfree.data.general.Dataset;
+
+/**
+ * This class implements the mapping between {@link Dataset} items (points in chart)
+ * and the corresponding {@link Feature Features}.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ */
+public abstract class Feature2DatasetMapping<E, F extends Dataset> {
+  /** Holds the {@link FeatureCollection} for the mapping */
+  protected FeatureCollection featureCollection = null;
+
+  /** Holds the {@link Dataset} for the mapping */
+  protected F dataset = null;
+
+  /**
+   * Creates a mapping. 
+   * @param fc a {@link FeatureCollection} (can be {@code null}) 
+   */
+  public Feature2DatasetMapping(FeatureCollection fc, F dataset) {
+    this.featureCollection = fc;
+    this.dataset           = dataset;
+  }
+
+  /**
+   * Returns the {@link FeatureCollection} the mapping is provided for.
+   */
+  public FeatureCollection getFeatureCollection() {
+    return featureCollection;
+  }
+
+  /**
+   * Returns the {@link Dataset} the mapping is provided for.
+   */
+  public F getDataset() {
+    return dataset;
+  }
+
+  /**
+   * Sets the mapping between a feature ID and a dataset item.
+   * @param featureID    feature ID
+   * @param itemID       defines the dataset item
+   */
+  public abstract void setMapping(String featureID, E itemID);
+  
+  /**
+   * Removes the mapping of a feature ID.
+   * @param fID feature ID
+   */
+  public abstract void removeMappingForFeatureID(String fID);
+  
+  /**
+   * Removes the mapping for a dataset item.
+   * @param itemID    dataset item
+   */
+  public abstract void removeMappingForDataItem(E itemID);
+
+  /**
+   * Returns the data items for a given feature ID.
+   * @param fID a feature ID
+   * @return {@code null} if no data item is registered for the feature ID
+   */
+  public abstract E getDataID(String fID);
+  
+  /**
+   * Returns the feature ID for a given data item.
+   * @param itemID a data item
+   * @return {@code null} if no feature ID is registered for the data item
+   */
+  public abstract String getFeatureID(E itemID);
+  
+}

Modified: trunk/src/schmitzm/jfree/feature/Feature2SeriesDatasetMapping.java
===================================================================
--- trunk/src/schmitzm/jfree/feature/Feature2SeriesDatasetMapping.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/feature/Feature2SeriesDatasetMapping.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,198 +1,216 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.jfree.feature;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.geotools.feature.Feature;
-import org.geotools.feature.FeatureCollection;
-import org.jfree.data.general.SeriesDataset;
-
-/**
- * This class implements the mapping between {@link SeriesDataset} items (points in chart)
- * and the corresponding {@link Feature Features}.
- * The structure of this mapping assumes that there can be multiple
- * dataset items for one feature (e.g. in each series), but only one feature
- * for each dataset item.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- */
-public class Feature2SeriesDatasetMapping extends Feature2DatasetMapping<Integer,SeriesDataset> {
-  /** Holds the data items ({@code Map<SeriesKey,ItemIndex>})
-   *  for each feature ID (String). */
-  protected Map<String,Map<Comparable,Integer>> fid2did = new HashMap<String, Map<Comparable,Integer>>();
-  /** Holds for each series the feature ID (String) for each data item. */
-  protected Map<Comparable,Map<Integer,String>> did2fid = new HashMap<Comparable,Map<Integer,String>>();
-  
-  /**
-   * Creates a mapping. 
-   * @param fc a {@link FeatureCollection} (can be {@code null})
-   * @param dataset a {@link SeriesDataset} 
-   */
-  public Feature2SeriesDatasetMapping(FeatureCollection fc, SeriesDataset dataset) {
-    super(fc, dataset);
-  }
-
-  /**
-   * Returns the key of the primary series.
-   */
-  public Comparable getPrimarySeriesKey() {
-    return dataset.getSeriesKey(0);
-  }
-  
-  /**
-   * Sets the mapping between a feature ID and a dataset item IN THE
-   * PRIMARY SERIES.
-   * @param featureID    feature ID
-   * @param itemID       defines the dataset item
-   */
-  public void setMapping(String featureID, Integer itemID) {
-    setMapping(featureID, null, itemID);
-  }
-
-  /**
-   * Sets the mapping between a feature ID and a dataset item.
-   * @param featureID    feature ID
-   * @param seriesKey    defines the series of corresponding dataset item (if
-   *                     {@code null} the primary series is used)
-   * @param itemID       defines the dataset item
-   */
-  public void setMapping(String featureID, Comparable seriesKey, int itemID) {
-    if ( seriesKey == null )
-      seriesKey = getPrimarySeriesKey();
-    // Mapping FeatureID --> (Series/Index)
-    Map<Comparable,Integer> itemIDs = fid2did.get(featureID);
-    if ( itemIDs == null ) {
-      itemIDs = new HashMap<Comparable, Integer>();
-      fid2did.put(featureID, itemIDs);
-    }
-    itemIDs.put(seriesKey, itemID);
-    
-    // Mapping (Series/Index) --> FeatureID
-    Map<Integer,String> featureIDs = did2fid.get(seriesKey);
-    if ( featureIDs == null ) {
-      featureIDs = new HashMap<Integer, String>();
-      did2fid.put(seriesKey, featureIDs);
-    }
-    featureIDs.put(itemID, featureID);
-  }
-  
-  /**
-   * Removes the mapping of a feature ID.
-   * @param fID feature ID
-   */
-  public void removeMappingForFeatureID(String fID) {
-    // remove mapping FeatureID --> (Series/Index)
-    Map<Comparable, Integer> itemIDs = fid2did.remove(fID);
-
-    // remove mapping (Series/Index) --> FeatureID
-    // for all item IDs referencing to the feature ID
-    for (Comparable seriesKey : itemIDs.keySet()) {
-      Map<Integer, String> featureIDs = did2fid.get(seriesKey);
-      for (Integer itemID : itemIDs.values())
-        featureIDs.remove(itemID);
-    }
-  }
-  
-  /**
-   * Removes the mapping for a dataset item IN THE
-   * PRIMARY SERIES.
-   * @param itemID    dataset item
-   */
-  public void removeMappingForDataItem(Integer itemID) {
-    removeMappingForDataItem(null,itemID);
-  }
-
-  /**
-   * Removes the mapping for a dataset item.
-   * @param seriesKey defines the series of the dataset item (if
-   *                  {@code null} the primary series is used)
-   * @param itemID    dataset item
-   */
-  public void removeMappingForDataItem(Comparable seriesKey, Integer itemID) {
-    if ( seriesKey == null )
-      seriesKey = getPrimarySeriesKey();
-    // remove mapping (Series/Index) --> FeatureID 
-    Map<Integer, String> featureIDs = did2fid.get(seriesKey);
-    String fID = null;
-    if ( featureIDs != null )
-      fID = featureIDs.remove(itemID);
-    
-    // remove mapping FeatureID --> (Series/Index)
-    if ( fID != null ) {
-      Map<Comparable, Integer> itemIDs = fid2did.remove(fID);
-      itemIDs.remove(seriesKey);
-    }  
-  }
-
-  /**
-   * Returns the data items for a given feature IN THE
-   * PRIMARY SERIES.
-   * @param fID a feature ID
-   * @return {@code null} if no data item is registered for the feature ID
-   */
-  public Integer getDataID(String fID) {
-    return getDataID(null,fID);
-  }
-
-  /**
-   * Returns the data items for a given feature ID.
-   * @param fID a feature ID
-   * @param seriesKey defines the series of the dataset item (if
-   *                  {@code null} the primary series is used)
-   * @return {@code null} if no data item is registered for the feature ID
-   */
-  public Integer getDataID(Comparable seriesKey, String fID) {
-    if ( seriesKey == null )
-      seriesKey = getPrimarySeriesKey();
-    Map<Comparable,Integer> seriesIDs = getDataIDs(fID);
-    if ( seriesIDs != null )
-      return seriesIDs.get(seriesKey);
-    return null;
-  }
-
-
-  /**
-   * Returns the data items (of all series) for a given feature ID.
-   * @param fID a feature ID
-   * @return {@code null} if no data item is registered for the feature ID
-   */
-  public Map<Comparable,Integer> getDataIDs(String fID) {
-    return fid2did.get(fID);
-  }
-  
-  /**
-   * Returns the feature ID for a given data item IN THE
-   * PRIMARY SERIES.
-   * @param itemID a data item
-   * @return {@code null} if no feature ID is registered for the data item
-   */
-  public String getFeatureID(Integer itemID) {
-    return getFeatureID(null,itemID);
-  }
-
-  /**
-   * Returns the feature ID for a given data item.
-   * @param seriesKey defines the series of the dataset item  (if
-   *                  {@code null} the primary series is used)
-   * @param itemID a data item
-   * @return {@code null} if no feature ID is registered for the data item
-   */
-  public String getFeatureID(Comparable seriesKey, Integer itemID) {
-    if ( seriesKey == null )
-      seriesKey = getPrimarySeriesKey();
-    Map<Integer,String> featureIDs = did2fid.get(seriesKey);
-    if ( featureIDs != null )
-      return featureIDs.get(itemID); 
-    return null;
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.jfree.feature;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.geotools.feature.Feature;
+import org.geotools.feature.FeatureCollection;
+import org.jfree.data.general.SeriesDataset;
+
+/**
+ * This class implements the mapping between {@link SeriesDataset} items (points in chart)
+ * and the corresponding {@link Feature Features}.
+ * The structure of this mapping assumes that there can be multiple
+ * dataset items for one feature (e.g. in each series), but only one feature
+ * for each dataset item.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ */
+public class Feature2SeriesDatasetMapping extends Feature2DatasetMapping<Integer,SeriesDataset> {
+  /** Holds the data items ({@code Map<SeriesKey,ItemIndex>})
+   *  for each feature ID (String). */
+  protected Map<String,Map<Comparable,Integer>> fid2did = new HashMap<String, Map<Comparable,Integer>>();
+  /** Holds for each series the feature ID (String) for each data item. */
+  protected Map<Comparable,Map<Integer,String>> did2fid = new HashMap<Comparable,Map<Integer,String>>();
+  
+  /**
+   * Creates a mapping. 
+   * @param fc a {@link FeatureCollection} (can be {@code null})
+   * @param dataset a {@link SeriesDataset} 
+   */
+  public Feature2SeriesDatasetMapping(FeatureCollection fc, SeriesDataset dataset) {
+    super(fc, dataset);
+  }
+
+  /**
+   * Returns the key of the primary series.
+   */
+  public Comparable getPrimarySeriesKey() {
+    return dataset.getSeriesKey(0);
+  }
+  
+  /**
+   * Sets the mapping between a feature ID and a dataset item IN THE
+   * PRIMARY SERIES.
+   * @param featureID    feature ID
+   * @param itemID       defines the dataset item
+   */
+  public void setMapping(String featureID, Integer itemID) {
+    setMapping(featureID, null, itemID);
+  }
+
+  /**
+   * Sets the mapping between a feature ID and a dataset item.
+   * @param featureID    feature ID
+   * @param seriesKey    defines the series of corresponding dataset item (if
+   *                     {@code null} the primary series is used)
+   * @param itemID       defines the dataset item
+   */
+  public void setMapping(String featureID, Comparable seriesKey, int itemID) {
+    if ( seriesKey == null )
+      seriesKey = getPrimarySeriesKey();
+    // Mapping FeatureID --> (Series/Index)
+    Map<Comparable,Integer> itemIDs = fid2did.get(featureID);
+    if ( itemIDs == null ) {
+      itemIDs = new HashMap<Comparable, Integer>();
+      fid2did.put(featureID, itemIDs);
+    }
+    itemIDs.put(seriesKey, itemID);
+    
+    // Mapping (Series/Index) --> FeatureID
+    Map<Integer,String> featureIDs = did2fid.get(seriesKey);
+    if ( featureIDs == null ) {
+      featureIDs = new HashMap<Integer, String>();
+      did2fid.put(seriesKey, featureIDs);
+    }
+    featureIDs.put(itemID, featureID);
+  }
+  
+  /**
+   * Removes the mapping of a feature ID.
+   * @param fID feature ID
+   */
+  public void removeMappingForFeatureID(String fID) {
+    // remove mapping FeatureID --> (Series/Index)
+    Map<Comparable, Integer> itemIDs = fid2did.remove(fID);
+
+    // remove mapping (Series/Index) --> FeatureID
+    // for all item IDs referencing to the feature ID
+    for (Comparable seriesKey : itemIDs.keySet()) {
+      Map<Integer, String> featureIDs = did2fid.get(seriesKey);
+      for (Integer itemID : itemIDs.values())
+        featureIDs.remove(itemID);
+    }
+  }
+  
+  /**
+   * Removes the mapping for a dataset item IN THE
+   * PRIMARY SERIES.
+   * @param itemID    dataset item
+   */
+  public void removeMappingForDataItem(Integer itemID) {
+    removeMappingForDataItem(null,itemID);
+  }
+
+  /**
+   * Removes the mapping for a dataset item.
+   * @param seriesKey defines the series of the dataset item (if
+   *                  {@code null} the primary series is used)
+   * @param itemID    dataset item
+   */
+  public void removeMappingForDataItem(Comparable seriesKey, Integer itemID) {
+    if ( seriesKey == null )
+      seriesKey = getPrimarySeriesKey();
+    // remove mapping (Series/Index) --> FeatureID 
+    Map<Integer, String> featureIDs = did2fid.get(seriesKey);
+    String fID = null;
+    if ( featureIDs != null )
+      fID = featureIDs.remove(itemID);
+    
+    // remove mapping FeatureID --> (Series/Index)
+    if ( fID != null ) {
+      Map<Comparable, Integer> itemIDs = fid2did.remove(fID);
+      itemIDs.remove(seriesKey);
+    }  
+  }
+
+  /**
+   * Returns the data items for a given feature IN THE
+   * PRIMARY SERIES.
+   * @param fID a feature ID
+   * @return {@code null} if no data item is registered for the feature ID
+   */
+  public Integer getDataID(String fID) {
+    return getDataID(null,fID);
+  }
+
+  /**
+   * Returns the data items for a given feature ID.
+   * @param fID a feature ID
+   * @param seriesKey defines the series of the dataset item (if
+   *                  {@code null} the primary series is used)
+   * @return {@code null} if no data item is registered for the feature ID
+   */
+  public Integer getDataID(Comparable seriesKey, String fID) {
+    if ( seriesKey == null )
+      seriesKey = getPrimarySeriesKey();
+    Map<Comparable,Integer> seriesIDs = getDataIDs(fID);
+    if ( seriesIDs != null )
+      return seriesIDs.get(seriesKey);
+    return null;
+  }
+
+
+  /**
+   * Returns the data items (of all series) for a given feature ID.
+   * @param fID a feature ID
+   * @return {@code null} if no data item is registered for the feature ID
+   */
+  public Map<Comparable,Integer> getDataIDs(String fID) {
+    return fid2did.get(fID);
+  }
+  
+  /**
+   * Returns the feature ID for a given data item IN THE
+   * PRIMARY SERIES.
+   * @param itemID a data item
+   * @return {@code null} if no feature ID is registered for the data item
+   */
+  public String getFeatureID(Integer itemID) {
+    return getFeatureID(null,itemID);
+  }
+
+  /**
+   * Returns the feature ID for a given data item.
+   * @param seriesKey defines the series of the dataset item  (if
+   *                  {@code null} the primary series is used)
+   * @param itemID a data item
+   * @return {@code null} if no feature ID is registered for the data item
+   */
+  public String getFeatureID(Comparable seriesKey, Integer itemID) {
+    if ( seriesKey == null )
+      seriesKey = getPrimarySeriesKey();
+    Map<Integer,String> featureIDs = did2fid.get(seriesKey);
+    if ( featureIDs != null )
+      return featureIDs.get(itemID); 
+    return null;
+  }
+}

Modified: trunk/src/schmitzm/jfree/feature/FeatureDatasetMetaData.java
===================================================================
--- trunk/src/schmitzm/jfree/feature/FeatureDatasetMetaData.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/feature/FeatureDatasetMetaData.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,41 +1,59 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.jfree.feature;
-
-import schmitzm.jfree.DatasetMetaDataGroup;
-
-/**
- * Meta data for dataset whose data bases on features.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- */
-public class FeatureDatasetMetaData extends DatasetMetaDataGroup {
-  /** Meta data ID for mapping between features and chart data. */
-  public static String KEY_MAPPING = "ID_MAPPING";
-  
-  /**
-   * Creates a new meta data object for features. 
-   * @param mapping mapping between features and chart data
-   */
-  public FeatureDatasetMetaData(Feature2DatasetMapping<?,?> mapping) {
-    super();
-    setMetaData(KEY_MAPPING, mapping);
-  }
-  
-  /**
-   * Returns the mapping between features and the corresponding
-   * dataset items.
-   */
-  public Feature2DatasetMapping<?,?> getMapping() {
-    return (Feature2DatasetMapping<?,?>)getMetaData(KEY_MAPPING);
-  }
-  
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.jfree.feature;
+
+import schmitzm.jfree.DatasetMetaDataGroup;
+
+/**
+ * Meta data for dataset whose data bases on features.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ */
+public class FeatureDatasetMetaData extends DatasetMetaDataGroup {
+  /** Meta data ID for mapping between features and chart data. */
+  public static String KEY_MAPPING = "ID_MAPPING";
+  
+  /**
+   * Creates a new meta data object for features. 
+   * @param mapping mapping between features and chart data
+   */
+  public FeatureDatasetMetaData(Feature2DatasetMapping<?,?> mapping) {
+    super();
+    setMetaData(KEY_MAPPING, mapping);
+  }
+  
+  /**
+   * Returns the mapping between features and the corresponding
+   * dataset items.
+   */
+  public Feature2DatasetMapping<?,?> getMapping() {
+    return (Feature2DatasetMapping<?,?>)getMetaData(KEY_MAPPING);
+  }
+  
+}

Modified: trunk/src/schmitzm/jfree/feature/FeatureDatasetSelectionModel.java
===================================================================
--- trunk/src/schmitzm/jfree/feature/FeatureDatasetSelectionModel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/feature/FeatureDatasetSelectionModel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,49 +1,68 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.jfree.feature;
-
-import java.util.Set;
-
-import org.jfree.data.general.Dataset;
-
-import schmitzm.jfree.chart.selection.DatasetSelectionModel;
-
-/**
- * This selection model maintains whether items of a {@link Dataset} corresponding
- * to features are selected in a chart or not.
- * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- */
-public interface FeatureDatasetSelectionModel<E extends Dataset> extends DatasetSelectionModel<E> {
-  /**
-   * Checks if the data item of a feature is selected.
-   * @param fID  feature ID
-   */
-  public boolean isFeatureSelected(String fID);
-  
-  /**
-   * Sets whether the data item of a feature is selected or not.
-   * @param fID  feature ID
-   * @param selected  flag to (de)select the item
-   */
-  public void setItemSelected(String fID, boolean selected);
-  
-  /**
-   * Changes the selection of the data item of a feature.
-   * @param fID  feature ID
-   * @return {@code true} if the item changed to selected 
-   */
-  public boolean changeItemSelection(String fID);
-  
-  /**
-   * Returns the IDs of the selected features.
-   */
-  public Set<String> getSelectedFeatures();
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.jfree.feature;
+
+import java.util.Set;
+
+import org.jfree.data.general.Dataset;
+
+import schmitzm.jfree.chart.selection.DatasetSelectionModel;
+
+/**
+ * This selection model maintains whether items of a {@link Dataset} corresponding
+ * to features are selected in a chart or not.
+ * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ */
+public interface FeatureDatasetSelectionModel<E extends Dataset> extends DatasetSelectionModel<E> {
+  /**
+   * Checks if the data item of a feature is selected.
+   * @param fID  feature ID
+   */
+  public boolean isFeatureSelected(String fID);
+  
+  /**
+   * Sets whether the data item of a feature is selected or not.
+   * @param fID  feature ID
+   * @param selected  flag to (de)select the item
+   */
+  public void setItemSelected(String fID, boolean selected);
+  
+  /**
+   * Changes the selection of the data item of a feature.
+   * @param fID  feature ID
+   * @return {@code true} if the item changed to selected 
+   */
+  public boolean changeItemSelection(String fID);
+  
+  /**
+   * Returns the IDs of the selected features.
+   */
+  public Set<String> getSelectedFeatures();
+}

Modified: trunk/src/schmitzm/jfree/feature/FeatureSeriesDatasetSelectionModel.java
===================================================================
--- trunk/src/schmitzm/jfree/feature/FeatureSeriesDatasetSelectionModel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/feature/FeatureSeriesDatasetSelectionModel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,135 +1,153 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.jfree.feature;
-
-import java.util.HashSet;
-import java.util.Set;
-
-import org.jfree.data.general.DatasetGroup;
-import org.jfree.data.general.SeriesDataset;
-
-import schmitzm.jfree.chart.selection.SeriesDatasetSelectionModel;
-import schmitzm.lang.LangUtil;
-
-/**
- * 
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- */
-public class FeatureSeriesDatasetSelectionModel extends SeriesDatasetSelectionModel implements FeatureDatasetSelectionModel<SeriesDataset> {
-  /** Holds the mapping between features and the corresponding item indices
-   *  of each series. */
-  protected Feature2SeriesDatasetMapping mapping = null;
-  
-  /**
-   * Creates a new selection model.
-   * @param dataset a dataset providing a {@link FeatureSeriesDatasetSelectionModel FeatureSeriesDatasetSelectionModel<Map<Comparable,Integer>>}
-   *                as dataset group
-   */
-  public FeatureSeriesDatasetSelectionModel(SeriesDataset dataset) {
-    super(dataset);
-    // DatasetGroup must provide meta data (containing the Feature<->DataItem mapping)
-    DatasetGroup group = dataset.getGroup();
-    if ( group == null || !(group instanceof FeatureDatasetMetaData) )
-      throw new UnsupportedOperationException("Dataset must provide FeatureDatasetMetaData as DatasetGroup: "+LangUtil.getSimpleClassName(group));
-    FeatureDatasetMetaData metadata = (FeatureDatasetMetaData)group;
-    // Meta data must provide Feature2SeriesDatasetMapping
-    Feature2DatasetMapping<?,?> mapping = metadata.getMapping();
-    if ( mapping == null || !(mapping instanceof Feature2SeriesDatasetMapping) )
-      throw new UnsupportedOperationException("Mapping (provided by FeatureDatasetMetaData) must be a Feature2SeriesDatasetMapping: "+LangUtil.getSimpleClassName(mapping));
-    this.mapping = (Feature2SeriesDatasetMapping)mapping;
-  }
-
-  /**
-   * Checks if the data item of a feature is selected in any series.
-   * @param fID  feature ID
-   */
-  public boolean isFeatureSelected(String fID) {
-    for (int i=0; i<dataset.getSeriesCount(); i++)
-      if ( isFeatureSelected(fID,dataset.getSeriesKey(i)) )
-        return true;
-    return false;
-    
-  }
-  
-  /**
-   * Checks if the data item of a feature is selected.
-   * @param fID  feature ID
-   * @param seriesKey series to check for the feature ID
-   */
-  public boolean isFeatureSelected(String fID, Comparable seriesKey) {
-    Integer dataItem = mapping.getDataID(seriesKey,fID);
-    return dataItem != null && isItemSelected(seriesKey, dataItem);
-  }
-
-  /**
-   * Sets the selection state for a feature in all dataset series.
-   * @param fID  feature ID
-   * @param selected  flag to (de)select the item
-   */
-  public void setItemSelected(String fID, boolean selected) {
-    for (int i=0; i<dataset.getSeriesCount(); i++)
-      setItemSelected(fID, dataset.getSeriesKey(i), selected);
-  }
-  
-  /**
-   * Sets whether the data item of a feature is selected or not.
-   * @param fID  feature ID
-   * @param seriesKey series to set the selection in
-   * @param selected  flag to (de)select the item
-   */
-  public void setItemSelected(String fID, Comparable seriesKey, boolean selected) {
-    Integer dataItem = mapping.getDataID(seriesKey,fID);
-    if ( dataItem == null )
-      LOGGER.warn("Feature unknown in Feature2DatasetItemDatasetGroup: "+fID);
-    else
-      setItemSelected(seriesKey, dataItem, selected);
-  }
-
-  /**
-   * Changes the selection of the data item of a feature in all
-   * series.
-   * @param fID  feature ID
-   * @return {@code true} if at least one item changed to selected 
-   */
-  public boolean changeItemSelection(String fID) {
-    boolean anyChangedToTrue = false;
-    for (int i=0; i<dataset.getSeriesCount(); i++)
-      anyChangedToTrue |= changeItemSelection(fID, dataset.getSeriesKey(i));
-    return anyChangedToTrue;
-  }
-
-  /**
-   * Changes the selection of the data item of a feature.
-   * @param fID  feature ID
-   * @param seriesKey series to change the selection in
-   * @return {@code true} if the item changed to selected 
-   */
-  public boolean changeItemSelection(String fID, Comparable seriesKey) {
-    Integer dataItem = mapping.getDataID(seriesKey,fID);
-    return changeItemSelection(seriesKey, dataItem);
-  }
-
-  /**
-  * Returns the IDs of the selected features (in any series).
-  */
-  public Set<String> getSelectedFeatures() {
-    Set<String> selectedFIDs = new HashSet<String>();
-    for (Comparable seriesKey : selectedSeriesIdx.keySet()) 
-      for (Integer selIdx : selectedSeriesIdx.get(seriesKey)) {
-        String selFID = mapping.getFeatureID(seriesKey,selIdx);
-        selectedFIDs.add(selFID);
-      }
-    
-    return selectedFIDs;
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.jfree.feature;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.jfree.data.general.DatasetGroup;
+import org.jfree.data.general.SeriesDataset;
+
+import schmitzm.jfree.chart.selection.SeriesDatasetSelectionModel;
+import schmitzm.lang.LangUtil;
+
+/**
+ * 
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ */
+public class FeatureSeriesDatasetSelectionModel extends SeriesDatasetSelectionModel implements FeatureDatasetSelectionModel<SeriesDataset> {
+  /** Holds the mapping between features and the corresponding item indices
+   *  of each series. */
+  protected Feature2SeriesDatasetMapping mapping = null;
+  
+  /**
+   * Creates a new selection model.
+   * @param dataset a dataset providing a {@link FeatureSeriesDatasetSelectionModel FeatureSeriesDatasetSelectionModel<Map<Comparable,Integer>>}
+   *                as dataset group
+   */
+  public FeatureSeriesDatasetSelectionModel(SeriesDataset dataset) {
+    super(dataset);
+    // DatasetGroup must provide meta data (containing the Feature<->DataItem mapping)
+    DatasetGroup group = dataset.getGroup();
+    if ( group == null || !(group instanceof FeatureDatasetMetaData) )
+      throw new UnsupportedOperationException("Dataset must provide FeatureDatasetMetaData as DatasetGroup: "+LangUtil.getSimpleClassName(group));
+    FeatureDatasetMetaData metadata = (FeatureDatasetMetaData)group;
+    // Meta data must provide Feature2SeriesDatasetMapping
+    Feature2DatasetMapping<?,?> mapping = metadata.getMapping();
+    if ( mapping == null || !(mapping instanceof Feature2SeriesDatasetMapping) )
+      throw new UnsupportedOperationException("Mapping (provided by FeatureDatasetMetaData) must be a Feature2SeriesDatasetMapping: "+LangUtil.getSimpleClassName(mapping));
+    this.mapping = (Feature2SeriesDatasetMapping)mapping;
+  }
+
+  /**
+   * Checks if the data item of a feature is selected in any series.
+   * @param fID  feature ID
+   */
+  public boolean isFeatureSelected(String fID) {
+    for (int i=0; i<dataset.getSeriesCount(); i++)
+      if ( isFeatureSelected(fID,dataset.getSeriesKey(i)) )
+        return true;
+    return false;
+    
+  }
+  
+  /**
+   * Checks if the data item of a feature is selected.
+   * @param fID  feature ID
+   * @param seriesKey series to check for the feature ID
+   */
+  public boolean isFeatureSelected(String fID, Comparable seriesKey) {
+    Integer dataItem = mapping.getDataID(seriesKey,fID);
+    return dataItem != null && isItemSelected(seriesKey, dataItem);
+  }
+
+  /**
+   * Sets the selection state for a feature in all dataset series.
+   * @param fID  feature ID
+   * @param selected  flag to (de)select the item
+   */
+  public void setItemSelected(String fID, boolean selected) {
+    for (int i=0; i<dataset.getSeriesCount(); i++)
+      setItemSelected(fID, dataset.getSeriesKey(i), selected);
+  }
+  
+  /**
+   * Sets whether the data item of a feature is selected or not.
+   * @param fID  feature ID
+   * @param seriesKey series to set the selection in
+   * @param selected  flag to (de)select the item
+   */
+  public void setItemSelected(String fID, Comparable seriesKey, boolean selected) {
+    Integer dataItem = mapping.getDataID(seriesKey,fID);
+    if ( dataItem == null )
+      LOGGER.warn("Feature unknown in Feature2DatasetItemDatasetGroup: "+fID);
+    else
+      setItemSelected(seriesKey, dataItem, selected);
+  }
+
+  /**
+   * Changes the selection of the data item of a feature in all
+   * series.
+   * @param fID  feature ID
+   * @return {@code true} if at least one item changed to selected 
+   */
+  public boolean changeItemSelection(String fID) {
+    boolean anyChangedToTrue = false;
+    for (int i=0; i<dataset.getSeriesCount(); i++)
+      anyChangedToTrue |= changeItemSelection(fID, dataset.getSeriesKey(i));
+    return anyChangedToTrue;
+  }
+
+  /**
+   * Changes the selection of the data item of a feature.
+   * @param fID  feature ID
+   * @param seriesKey series to change the selection in
+   * @return {@code true} if the item changed to selected 
+   */
+  public boolean changeItemSelection(String fID, Comparable seriesKey) {
+    Integer dataItem = mapping.getDataID(seriesKey,fID);
+    return changeItemSelection(seriesKey, dataItem);
+  }
+
+  /**
+  * Returns the IDs of the selected features (in any series).
+  */
+  public Set<String> getSelectedFeatures() {
+    Set<String> selectedFIDs = new HashSet<String>();
+    for (Comparable seriesKey : selectedSeriesIdx.keySet()) 
+      for (Integer selIdx : selectedSeriesIdx.get(seriesKey)) {
+        String selFID = mapping.getFeatureID(seriesKey,selIdx);
+        selectedFIDs.add(selFID);
+      }
+    
+    return selectedFIDs;
+  }
+
+}

Modified: trunk/src/schmitzm/jfree/feature/style/FeatureBasicChartStyle.java
===================================================================
--- trunk/src/schmitzm/jfree/feature/style/FeatureBasicChartStyle.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/feature/style/FeatureBasicChartStyle.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,103 +1,121 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.jfree.feature.style;
-
-import org.geotools.feature.FeatureCollection;
-import org.jfree.chart.JFreeChart;
-import org.jfree.chart.plot.PlotOrientation;
-import org.jfree.data.general.Dataset;
-
-import schmitzm.jfree.JFreeChartUtil;
-import schmitzm.jfree.chart.style.BasicChartStyle;
-import schmitzm.jfree.chart.style.ChartType;
-
-/**
- * This class extends the {@link BasicChartStyle} with the properties
- * of the {@link FeatureChartStyle}.<br>
- * After instantiation the 2 feature attributes used to define the chart
- * data must be set by {@link #setAttributeName(int, String)}. Without
- * setting the attributes the style can not be applied to a feature collection!
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- */
-public class FeatureBasicChartStyle extends BasicChartStyle implements FeatureChartStyle {
-  /** Used to maintain the {@link FeatureChartStyle} properties. */
-  protected Dummy dummyFeatureChartStyle = null;
-  
-  /**
-   * Creates a normal line style with default values.
-   * @param id a (unique) ID for the style
-   */
-  public FeatureBasicChartStyle(String id) {
-    this(id, ChartType.LINE);
-  }
-
-  /**
-   * Creates a normal, vertical line, bar or area style.
-   * @param id   a (unique) ID for the style
-   * @param type type of the chart layout
-   */
-  public FeatureBasicChartStyle(String id, ChartType type) {
-    super(id, type);
-    dummyFeatureChartStyle = new Dummy(id, 2);
-  }
-
-  /**
-   * Returns the attribute count needed to specify the chart data
-   * from feature collection.
-   * @return always 2
-   */
-  @Override
-  public int getAttributeCount() {
-    return dummyFeatureChartStyle.getAttributeCount();
-  }
-
-  /**
-   * Returns the name of a feature attribute needed to create a
-   * chart for this style.
-   * @param idx axis index
-   * @see ChartStyle#DOMAIN_AXIS
-   * @see ChartStyle#RANGE_AXIS
-   * @see ChartStyle#RANGE_AXIS2
-   */
-  public String getAttributeName(int idx) {
-    return dummyFeatureChartStyle.getAttributeName(idx);
-  }
-
-  /**
-   * Sets the name of a feature attribute needed to create a
-   * chart for this style.
-   * @param idx axis index
-   * @param attrName feature attribute name 
-   * @see ChartStyle#DOMAIN_AXIS
-   * @see ChartStyle#RANGE_AXIS
-   * @see ChartStyle#RANGE_AXIS2
-   */
-  @Override
-  public void setAttributeName(int idx, String attrName) {
-    dummyFeatureChartStyle.setAttributeName(idx,attrName);
-  }
-  
-  /**
-   * Creates an appropriate {@link Dataset} for the attributes defined
-   * by this style (according to the attributes types in the given
-   * {@link FeatureCollection}) and calls {@link #applyToDataset(Dataset)}.
-   * @see schmitzm.jfree.feature.style.FeatureChartStyle#applyToFeatureCollection(org.geotools.feature.FeatureCollection)
-   */
-  @Override
-  public JFreeChart applyToFeatureCollection(FeatureCollection fc) {
-//    Dataset dataset = null; // TODO: Create dataset from FeatureCollection by utility method
-    Dataset dataset = JFreeChartUtil.createXYDataset(fc, getTitleStyle().getLabel(), getAttributeName(DOMAIN_AXIS), getAttributeName(RANGE_AXIS));
-    return applyToDataset(dataset);
-  }
-
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.jfree.feature.style;
+
+import org.geotools.feature.FeatureCollection;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.data.general.Dataset;
+
+import schmitzm.jfree.JFreeChartUtil;
+import schmitzm.jfree.chart.style.BasicChartStyle;
+import schmitzm.jfree.chart.style.ChartType;
+
+/**
+ * This class extends the {@link BasicChartStyle} with the properties
+ * of the {@link FeatureChartStyle}.<br>
+ * After instantiation the 2 feature attributes used to define the chart
+ * data must be set by {@link #setAttributeName(int, String)}. Without
+ * setting the attributes the style can not be applied to a feature collection!
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ */
+public class FeatureBasicChartStyle extends BasicChartStyle implements FeatureChartStyle {
+  /** Used to maintain the {@link FeatureChartStyle} properties. */
+  protected Dummy dummyFeatureChartStyle = null;
+  
+  /**
+   * Creates a normal line style with default values.
+   * @param id a (unique) ID for the style
+   */
+  public FeatureBasicChartStyle(String id) {
+    this(id, ChartType.LINE);
+  }
+
+  /**
+   * Creates a normal, vertical line, bar or area style.
+   * @param id   a (unique) ID for the style
+   * @param type type of the chart layout
+   */
+  public FeatureBasicChartStyle(String id, ChartType type) {
+    super(id, type);
+    dummyFeatureChartStyle = new Dummy(id, 2);
+  }
+
+  /**
+   * Returns the attribute count needed to specify the chart data
+   * from feature collection.
+   * @return always 2
+   */
+  @Override
+  public int getAttributeCount() {
+    return dummyFeatureChartStyle.getAttributeCount();
+  }
+
+  /**
+   * Returns the name of a feature attribute needed to create a
+   * chart for this style.
+   * @param idx axis index
+   * @see ChartStyle#DOMAIN_AXIS
+   * @see ChartStyle#RANGE_AXIS
+   * @see ChartStyle#RANGE_AXIS2
+   */
+  public String getAttributeName(int idx) {
+    return dummyFeatureChartStyle.getAttributeName(idx);
+  }
+
+  /**
+   * Sets the name of a feature attribute needed to create a
+   * chart for this style.
+   * @param idx axis index
+   * @param attrName feature attribute name 
+   * @see ChartStyle#DOMAIN_AXIS
+   * @see ChartStyle#RANGE_AXIS
+   * @see ChartStyle#RANGE_AXIS2
+   */
+  @Override
+  public void setAttributeName(int idx, String attrName) {
+    dummyFeatureChartStyle.setAttributeName(idx,attrName);
+  }
+  
+  /**
+   * Creates an appropriate {@link Dataset} for the attributes defined
+   * by this style (according to the attributes types in the given
+   * {@link FeatureCollection}) and calls {@link #applyToDataset(Dataset)}.
+   * @see schmitzm.jfree.feature.style.FeatureChartStyle#applyToFeatureCollection(org.geotools.feature.FeatureCollection)
+   */
+  @Override
+  public JFreeChart applyToFeatureCollection(FeatureCollection fc) {
+//    Dataset dataset = null; // TODO: Create dataset from FeatureCollection by utility method
+    Dataset dataset = JFreeChartUtil.createXYDataset(fc, getTitleStyle().getLabel(), getAttributeName(DOMAIN_AXIS), getAttributeName(RANGE_AXIS));
+    return applyToDataset(dataset);
+  }
+
+
+}

Modified: trunk/src/schmitzm/jfree/feature/style/FeatureChartStyle.java
===================================================================
--- trunk/src/schmitzm/jfree/feature/style/FeatureChartStyle.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/feature/style/FeatureChartStyle.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,16 +1,34 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.jfree.feature.style;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.jfree.feature.style;
-
 import java.awt.Paint;
 import java.util.ArrayList;
 import java.util.List;
@@ -26,13 +44,13 @@
 import schmitzm.jfree.chart.style.ChartPlotStyle;
 import schmitzm.jfree.chart.style.ChartRendererStyle;
 import schmitzm.jfree.chart.style.ChartStyle;
-
-/**
+
+/**
  * This interface extends the chart style with several functionalities
- * used to define a chart on a {@link FeatureCollection}.
- * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
- * @version 1.0
- */
+ * used to define a chart on a {@link FeatureCollection}.
+ * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
+ * @version 1.0
+ */
 public interface FeatureChartStyle extends ChartStyle {
   /**
    * Returns the number of feature attributes needed to create a
@@ -156,4 +174,4 @@
     }
 
 }
-}
+}

Modified: trunk/src/schmitzm/jfree/feature/style/FeatureChartStyleXMLFactory.java
===================================================================
--- trunk/src/schmitzm/jfree/feature/style/FeatureChartStyleXMLFactory.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/feature/style/FeatureChartStyleXMLFactory.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,16 +1,34 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.jfree.feature.style;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.jfree.feature.style;
-
 import java.util.List;
 
 import org.geotools.feature.FeatureCollection;
@@ -23,12 +41,12 @@
 import schmitzm.lang.LangUtil;
 import schmitzm.xml.XMLUtil;
 
-/**
+/**
  * This class defines a factory to create a chart style from XML
- * specialized for {@link FeatureCollection}.
- * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
- * @version 1.0
- */
+ * specialized for {@link FeatureCollection}.
+ * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
+ * @version 1.0
+ */
 public class FeatureChartStyleXMLFactory extends ChartStyleXMLFactory<FeatureChartStyle> {
 
   /**
@@ -117,4 +135,4 @@
   }
 
 
-}
+}

Modified: trunk/src/schmitzm/jfree/feature/style/FeatureChartUtil.java
===================================================================
--- trunk/src/schmitzm/jfree/feature/style/FeatureChartUtil.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/feature/style/FeatureChartUtil.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,27 +1,45 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.jfree.feature.style;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.jfree.feature.style;
-
 import org.geotools.feature.FeatureCollection;
 
 import schmitzm.jfree.chart.style.ChartStyleXMLFactory;
 
-/**
+/**
  * This class contains static utility methods related to chart styles based on
- * {@link FeatureCollection}.
- * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
- * @version 1.0
- */
+ * {@link FeatureCollection}.
+ * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
+ * @version 1.0
+ */
 public class FeatureChartUtil {
   /** Instance of {@link ChartStyleXMLFactory}. */
   public static final FeatureChartStyleXMLFactory FEATURE_CHART_STYLE_FACTORY = new FeatureChartStyleXMLFactory();
-}
+}

Modified: trunk/src/schmitzm/jfree/feature/style/FeatureScatterChartStyle.java
===================================================================
--- trunk/src/schmitzm/jfree/feature/style/FeatureScatterChartStyle.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/feature/style/FeatureScatterChartStyle.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,99 +1,117 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.jfree.feature.style;
-
-import org.geotools.feature.FeatureCollection;
-import org.jfree.chart.JFreeChart;
-import org.jfree.chart.plot.PlotOrientation;
-import org.jfree.data.general.Dataset;
-
-import schmitzm.jfree.JFreeChartUtil;
-import schmitzm.jfree.chart.style.BasicChartStyle;
-import schmitzm.jfree.chart.style.ScatterChartStyle;
-
-/**
- * This class extends the {@link ScatterChartStyle} with the properties
- * of the {@link FeatureChartStyle}.<br>
- * After instantiation the 2 feature attributes used to define the chart
- * data must be set by {@link #setAttributeName(int, String)}. Without
- * setting the attributes the style can not be applied to a feature collection!
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- */
-public class FeatureScatterChartStyle extends ScatterChartStyle implements FeatureChartStyle {
-  /** Used to maintain the {@link FeatureChartStyle} properties. */
-  protected Dummy dummyFeatureChartStyle = null;
-  
-  /**
-   * Creates a scatter chart style a regression line shown.
-   * @param id   a (unique) ID for the style
-   */
-  public FeatureScatterChartStyle(String id) {
-    super(id);
-    dummyFeatureChartStyle = new Dummy(id,2);
-  }
-
-  /**
-   * Returns the attribute count needed to specify the chart data
-   * from feature collection.
-   * @return always 2
-   */
-  @Override
-  public int getAttributeCount() {
-    return dummyFeatureChartStyle.getAttributeCount();
-  }
-
-  /**
-   * Returns the name of a feature attribute needed to create a
-   * chart for this style.
-   * @param idx axis index
-   * @see ChartStyle#DOMAIN_AXIS
-   * @see ChartStyle#RANGE_AXIS
-   * @see ChartStyle#RANGE_AXIS2
-   */
-  public String getAttributeName(int idx) {
-    return dummyFeatureChartStyle.getAttributeName(idx);
-  }
-
-  /**
-   * Sets the name of a feature attribute needed to create a
-   * chart for this style.
-   * @param idx axis index
-   * @param attrName feature attribute name 
-   * @see ChartStyle#DOMAIN_AXIS
-   * @see ChartStyle#RANGE_AXIS
-   * @see ChartStyle#RANGE_AXIS2
-   */
-  public void setAttributeName(int idx, String attrName) {
-    dummyFeatureChartStyle.setAttributeName(idx,attrName);
-  }
-
-  /**
-   * Creates an appropriate {@link Dataset} for the attributes defined
-   * by this style (according to the attributes types in the given
-   * {@link FeatureCollection}) and calls {@link #applyToDataset(Dataset)}.
-   * @see schmitzm.jfree.feature.style.FeatureChartStyle#applyToFeatureCollection(org.geotools.feature.FeatureCollection)
-   */
-  @Override
-  public JFreeChart applyToFeatureCollection(FeatureCollection fc) {
-    // TODO: Check the attribute data and create a CategoryDataset if
-    //       a non-numeric column is specified
-    Dataset dataset = JFreeChartUtil.createXYDataset(
-        fc,
-        getTitleStyle().getLabel(),
-        getAttributeName(0),
-        getAttributeName(1)
-    );
-    return applyToDataset(dataset);
-  }
-
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.jfree.feature.style;
+
+import org.geotools.feature.FeatureCollection;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.plot.PlotOrientation;
+import org.jfree.data.general.Dataset;
+
+import schmitzm.jfree.JFreeChartUtil;
+import schmitzm.jfree.chart.style.BasicChartStyle;
+import schmitzm.jfree.chart.style.ScatterChartStyle;
+
+/**
+ * This class extends the {@link ScatterChartStyle} with the properties
+ * of the {@link FeatureChartStyle}.<br>
+ * After instantiation the 2 feature attributes used to define the chart
+ * data must be set by {@link #setAttributeName(int, String)}. Without
+ * setting the attributes the style can not be applied to a feature collection!
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ */
+public class FeatureScatterChartStyle extends ScatterChartStyle implements FeatureChartStyle {
+  /** Used to maintain the {@link FeatureChartStyle} properties. */
+  protected Dummy dummyFeatureChartStyle = null;
+  
+  /**
+   * Creates a scatter chart style a regression line shown.
+   * @param id   a (unique) ID for the style
+   */
+  public FeatureScatterChartStyle(String id) {
+    super(id);
+    dummyFeatureChartStyle = new Dummy(id,2);
+  }
+
+  /**
+   * Returns the attribute count needed to specify the chart data
+   * from feature collection.
+   * @return always 2
+   */
+  @Override
+  public int getAttributeCount() {
+    return dummyFeatureChartStyle.getAttributeCount();
+  }
+
+  /**
+   * Returns the name of a feature attribute needed to create a
+   * chart for this style.
+   * @param idx axis index
+   * @see ChartStyle#DOMAIN_AXIS
+   * @see ChartStyle#RANGE_AXIS
+   * @see ChartStyle#RANGE_AXIS2
+   */
+  public String getAttributeName(int idx) {
+    return dummyFeatureChartStyle.getAttributeName(idx);
+  }
+
+  /**
+   * Sets the name of a feature attribute needed to create a
+   * chart for this style.
+   * @param idx axis index
+   * @param attrName feature attribute name 
+   * @see ChartStyle#DOMAIN_AXIS
+   * @see ChartStyle#RANGE_AXIS
+   * @see ChartStyle#RANGE_AXIS2
+   */
+  public void setAttributeName(int idx, String attrName) {
+    dummyFeatureChartStyle.setAttributeName(idx,attrName);
+  }
+
+  /**
+   * Creates an appropriate {@link Dataset} for the attributes defined
+   * by this style (according to the attributes types in the given
+   * {@link FeatureCollection}) and calls {@link #applyToDataset(Dataset)}.
+   * @see schmitzm.jfree.feature.style.FeatureChartStyle#applyToFeatureCollection(org.geotools.feature.FeatureCollection)
+   */
+  @Override
+  public JFreeChart applyToFeatureCollection(FeatureCollection fc) {
+    // TODO: Check the attribute data and create a CategoryDataset if
+    //       a non-numeric column is specified
+    Dataset dataset = JFreeChartUtil.createXYDataset(
+        fc,
+        getTitleStyle().getLabel(),
+        getAttributeName(0),
+        getAttributeName(1)
+    );
+    return applyToDataset(dataset);
+  }
+
+
+}

Modified: trunk/src/schmitzm/jfree/resource/locales/JFreeResourceBundle.properties
===================================================================
--- trunk/src/schmitzm/jfree/resource/locales/JFreeResourceBundle.properties	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/resource/locales/JFreeResourceBundle.properties	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,18 +1,47 @@
-# --------------------------------------------------------------------------
-# ------ Default Translations (english) for JFreeChart GUI components ------
-# ------ in Package schmitz.jfree                                     ------
-# --------------------------------------------------------------------------
-
-# Diagram types
-diagram.points=Points
-diagram.lines=Lines
-diagram.bars=Bars
-diagram.areas=Areas
-
-ChartType_BAR.Desc=Its a great thing to have a few barcharts at hand.
-ChartType_BAR.Title=Barchart
-
-ChartType_SCATTER.Title=Scatterplot
-ChartType_PIE.Title=Piechart
-ChartType_AREA.Title=Areachart
-ChartType_LINE.Title=Linechart
\ No newline at end of file
+##########
+#Copyright (c) 2009 Martin O. J. Schmitz.
+#
+#This file is part of the SCHMITZM library - a collection of utility 
+#classes based on Java 1.6, focussing (not only) on Java Swing 
+#and the Geotools library.
+#
+#The SCHMITZM project is hosted at:
+#http://wald.intevation.org/projects/schmitzm/
+#
+#This program is free software; you can redistribute it and/or
+#modify it under the terms of the GNU Lesser General Public License
+#as published by the Free Software Foundation; either version 3
+#of the License, or (at your option) any later version.
+#
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+#
+#You should have received a copy of the GNU Lesser General Public License (license.txt)
+#along with this program; if not, write to the Free Software
+#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#or try this link: http://www.gnu.org/licenses/lgpl.html
+#
+#Contributors:
+#    Martin O. J. Schmitz - initial API and implementation
+#    Stefan A. Krüger - additional utility classes
+##########
+# --------------------------------------------------------------------------
+# ------ Default Translations (english) for JFreeChart GUI components ------
+# ------ in Package schmitz.jfree                                     ------
+# --------------------------------------------------------------------------
+
+# Diagram types
+diagram.points=Points
+diagram.lines=Lines
+diagram.bars=Bars
+diagram.areas=Areas
+
+ChartType_BAR.Desc=Its a great thing to have a few barcharts at hand.
+ChartType_BAR.Title=Barchart
+
+ChartType_SCATTER.Title=Scatterplot
+ChartType_PIE.Title=Piechart
+ChartType_AREA.Title=Areachart
+ChartType_LINE.Title=Linechart

Modified: trunk/src/schmitzm/jfree/resource/locales/JFreeResourceBundle_de.properties
===================================================================
--- trunk/src/schmitzm/jfree/resource/locales/JFreeResourceBundle_de.properties	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/jfree/resource/locales/JFreeResourceBundle_de.properties	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,18 +1,47 @@
-# ---------------------------------------------------------------
-# ------ German Translations for JFreeChart GUI components ------
-# ------ in Package schmitz.jfree                          ------
-# ---------------------------------------------------------------
-
-# Diagram types
-diagram.points=Punkte
-diagram.lines=Linien
-diagram.bars=Balken
-diagram.areas=Flächen
-
-ChartType_BAR.Desc=<html>Ein Balkendiagram ist eine tolle Sache.</html>
-ChartType_BAR.Title=Balkendiagramm
-
-ChartType_SCATTER.Title=Streudiagramm
-ChartType_PIE.Title=Kreisdiagramm
-ChartType_AREA.Title=Flächendiagramm
-ChartType_LINE.Title=Liniendiagramm
\ No newline at end of file
+##########
+#Copyright (c) 2009 Martin O. J. Schmitz.
+#
+#This file is part of the SCHMITZM library - a collection of utility 
+#classes based on Java 1.6, focussing (not only) on Java Swing 
+#and the Geotools library.
+#
+#The SCHMITZM project is hosted at:
+#http://wald.intevation.org/projects/schmitzm/
+#
+#This program is free software; you can redistribute it and/or
+#modify it under the terms of the GNU Lesser General Public License
+#as published by the Free Software Foundation; either version 3
+#of the License, or (at your option) any later version.
+#
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+#
+#You should have received a copy of the GNU Lesser General Public License (license.txt)
+#along with this program; if not, write to the Free Software
+#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#or try this link: http://www.gnu.org/licenses/lgpl.html
+#
+#Contributors:
+#    Martin O. J. Schmitz - initial API and implementation
+#    Stefan A. Krüger - additional utility classes
+##########
+# ---------------------------------------------------------------
+# ------ German Translations for JFreeChart GUI components ------
+# ------ in Package schmitz.jfree                          ------
+# ---------------------------------------------------------------
+
+# Diagram types
+diagram.points=Punkte
+diagram.lines=Linien
+diagram.bars=Balken
+diagram.areas=Flächen
+
+ChartType_BAR.Desc=<html>Ein Balkendiagram ist eine tolle Sache.</html>
+ChartType_BAR.Title=Balkendiagramm
+
+ChartType_SCATTER.Title=Streudiagramm
+ChartType_PIE.Title=Kreisdiagramm
+ChartType_AREA.Title=Flächendiagramm
+ChartType_LINE.Title=Liniendiagramm

Modified: trunk/src/schmitzm/lang/AbstractNamedObject.java
===================================================================
--- trunk/src/schmitzm/lang/AbstractNamedObject.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/lang/AbstractNamedObject.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,37 +1,55 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.lang;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+/**
+ * Diese Klasse bildet eine Basis-Implementierung von {@link NamedObject}
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public abstract class AbstractNamedObject implements NamedObject {
+  /** Speichert den Namen des Objekts. */
+  protected String name = "";
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+  /**
+   * Liefert den Namen des Objekts.
+   */
+  public String getName() {
+    return name;
+  }
 
-package schmitzm.lang;
-
-/**
- * Diese Klasse bildet eine Basis-Implementierung von {@link NamedObject}
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public abstract class AbstractNamedObject implements NamedObject {
-  /** Speichert den Namen des Objekts. */
-  protected String name = "";
-
-  /**
-   * Liefert den Namen des Objekts.
-   */
-  public String getName() {
-    return name;
-  }
-
-  /**
-   * Setzt den Namen des Objekts.
-   * @param name neuer Name
-   */
-  public void setName(String name) {
-    this.name = name;
-  }
-}
+  /**
+   * Setzt den Namen des Objekts.
+   * @param name neuer Name
+   */
+  public void setName(String name) {
+    this.name = name;
+  }
+}

Modified: trunk/src/schmitzm/lang/AlreadyHandledException.java
===================================================================
--- trunk/src/schmitzm/lang/AlreadyHandledException.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/lang/AlreadyHandledException.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,36 +1,54 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.lang;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+/**
+ * Diese Exception stellt einen Fehler dar, der bereits "irgendwo" abgefangen
+ * wurde. Die zeit nur an, DASS ein Fehler aufgetreten ist, dieser aber nicht
+ * mehr (mit einer Fehlermeldung) verarbeitet werden muss.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class AlreadyHandledException extends RuntimeException {
+  /**
+   * Erzeugt eine neue <code>AlreadyHandledException</code>.
+   */
+  public AlreadyHandledException() {
+    this(null);
+  }
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.lang;
-
-/**
- * Diese Exception stellt einen Fehler dar, der bereits "irgendwo" abgefangen
- * wurde. Die zeit nur an, DASS ein Fehler aufgetreten ist, dieser aber nicht
- * mehr (mit einer Fehlermeldung) verarbeitet werden muss.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class AlreadyHandledException extends RuntimeException {
-  /**
-   * Erzeugt eine neue <code>AlreadyHandledException</code>.
-   */
-  public AlreadyHandledException() {
-    this(null);
-  }
-
-  /**
-   * Erzeugt eine neue <code>AlreadyHandledException</code>.
-   * @param mess Meldung
-   */
-  public AlreadyHandledException(String mess) {
-    super(mess);
-  }
-}
+  /**
+   * Erzeugt eine neue <code>AlreadyHandledException</code>.
+   * @param mess Meldung
+   */
+  public AlreadyHandledException(String mess) {
+    super(mess);
+  }
+}

Modified: trunk/src/schmitzm/lang/ComparableObject.java
===================================================================
--- trunk/src/schmitzm/lang/ComparableObject.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/lang/ComparableObject.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,105 +1,123 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.lang;
-
-// nur fuer Doku
-import java.util.TreeSet;
-
-/**
- * Diese Klasse dient dazu, ein beliebiges Objekt <b>{@linkplain Comparable vergleichbar}</b>
- * zu machen. Hierzu verbindet eine diese <code>ComparableObject</code>
- * das Objekt mit einem {@linkplain Comparable vergleichbaren} Key, so dass
- * ein Tupel <K,V> entsteht, welches z.B. in ein {@link TreeSet} eingefuegt
- * werden kann.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class ComparableObject<K extends Comparable,V> implements Comparable {
-  private K       key    = null;
-  private V       obj    = null;
-  private boolean onlyObj = false;
-
-  /**
-   * Erzeugt ein neues Tupel
-   * @param key  Key-Wert ueber den das Objekt verglichen wird
-   *             (muss eine {@link Comparable}-Instanz sein!)
-   * @param obj  beliebiges Objekt, dem der Key <code>key</code> zugeordnet ist
-   */
-  public ComparableObject(K key, V obj) {
-    this(key,obj,false);
-  }
-
-  /**
-   * Erzeugt ein neues Tupel
-   * @param key     Key-Wert ueber den das Objekt verglichen wird
-   *                (muss eine {@link Comparable}-Instanz sein!)
-   * @param obj     beliebiges Objekt, dem der Key <code>key</code> zugeordnet ist
-   * @param onlyObj wenn <code>true</code> wird in der {@link #equals(Object)}-Methode
-   *                nur auf <code>obj</code> verglichen. Standardmaessig vergleicht
-   *                die {@link #equals(Object)}-Methode <code>obj</code> und
-   *                <code>key</code>.
-   */
-  public ComparableObject(K key, V obj, boolean onlyObj) {
-    this.key = key;
-    this.obj = obj;
-    this.onlyObj = onlyObj;
-  }
-
-  /**
-   * Liefert das Objekt.
-   */
-  public V getObject() {
-    return obj;
-  }
-
-  /**
-   * Liefert den Schluessel.
-   */
-  public K getKey() {
-    return key;
-  }
-
-  /**
-   * Vergleicht den Schluessel dieses Objekts mit einem anderen. Liefert nur 0,
-   * wenn <code>o</code> mit <code>this</code> uebereinstimmt!
-   * @param o zu vergleichendes Objekt (kann ein anderes <code>ComparableObject</code>
-   *          sein oder eine {@link Comparable}-Instanz)
-   * @return einen <b>negativen</b> Wert, falls dieses Objekt <i>kleiner</i> ist als <code>o</code>;<br>
-   *         einen <b>positiven</b> Wert, falls dieses Objekt <i>groesser</i> ist als <code>o</code>;<br>
-   *         <b>0</b>, falls die beiden Objekte identisch sind
-   */
-  public int compareTo(Object o) {
-    if ( this == o || this.equals(o) )
-      return 0;
-
-    int comp = ( o instanceof ComparableObject ) ? key.compareTo( ((ComparableObject)o).getKey() ) : key.compareTo(o);
-    if ( comp == 0 ) {
-      comp = ( this.hashCode() < o.hashCode() ) ? -1 : 1;
-    }
-    return comp;
-  }
-
-  /**
-   * Vergleicht das <code>ComparableObject</code> mit einem anderen. Wurde im
-   * {@linkplain #ComparableObject(K,V,boolean) Konstruktor} das <code>onlyObj</code>-Flag
-   * auf <code>true</code> gesetzt, wird an dieser Stelle nur das Objekt
-   * auf Gleichheit verglichen, ansonsten auch der Key.
-   * @param o ein anderes <code>ComparableObject</code>
-   */
-  public boolean equals(Object o) {
-    if ( !(o instanceof ComparableObject) )
-      return false;
-    ComparableObject c = (ComparableObject)o;
-    return this.obj.equals(c.getObject()) && (onlyObj || this.key.equals(c.getKey()));
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.lang;
+
+// nur fuer Doku
+import java.util.TreeSet;
+
+/**
+ * Diese Klasse dient dazu, ein beliebiges Objekt <b>{@linkplain Comparable vergleichbar}</b>
+ * zu machen. Hierzu verbindet eine diese <code>ComparableObject</code>
+ * das Objekt mit einem {@linkplain Comparable vergleichbaren} Key, so dass
+ * ein Tupel <K,V> entsteht, welches z.B. in ein {@link TreeSet} eingefuegt
+ * werden kann.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class ComparableObject<K extends Comparable,V> implements Comparable {
+  private K       key    = null;
+  private V       obj    = null;
+  private boolean onlyObj = false;
+
+  /**
+   * Erzeugt ein neues Tupel
+   * @param key  Key-Wert ueber den das Objekt verglichen wird
+   *             (muss eine {@link Comparable}-Instanz sein!)
+   * @param obj  beliebiges Objekt, dem der Key <code>key</code> zugeordnet ist
+   */
+  public ComparableObject(K key, V obj) {
+    this(key,obj,false);
+  }
+
+  /**
+   * Erzeugt ein neues Tupel
+   * @param key     Key-Wert ueber den das Objekt verglichen wird
+   *                (muss eine {@link Comparable}-Instanz sein!)
+   * @param obj     beliebiges Objekt, dem der Key <code>key</code> zugeordnet ist
+   * @param onlyObj wenn <code>true</code> wird in der {@link #equals(Object)}-Methode
+   *                nur auf <code>obj</code> verglichen. Standardmaessig vergleicht
+   *                die {@link #equals(Object)}-Methode <code>obj</code> und
+   *                <code>key</code>.
+   */
+  public ComparableObject(K key, V obj, boolean onlyObj) {
+    this.key = key;
+    this.obj = obj;
+    this.onlyObj = onlyObj;
+  }
+
+  /**
+   * Liefert das Objekt.
+   */
+  public V getObject() {
+    return obj;
+  }
+
+  /**
+   * Liefert den Schluessel.
+   */
+  public K getKey() {
+    return key;
+  }
+
+  /**
+   * Vergleicht den Schluessel dieses Objekts mit einem anderen. Liefert nur 0,
+   * wenn <code>o</code> mit <code>this</code> uebereinstimmt!
+   * @param o zu vergleichendes Objekt (kann ein anderes <code>ComparableObject</code>
+   *          sein oder eine {@link Comparable}-Instanz)
+   * @return einen <b>negativen</b> Wert, falls dieses Objekt <i>kleiner</i> ist als <code>o</code>;<br>
+   *         einen <b>positiven</b> Wert, falls dieses Objekt <i>groesser</i> ist als <code>o</code>;<br>
+   *         <b>0</b>, falls die beiden Objekte identisch sind
+   */
+  public int compareTo(Object o) {
+    if ( this == o || this.equals(o) )
+      return 0;
+
+    int comp = ( o instanceof ComparableObject ) ? key.compareTo( ((ComparableObject)o).getKey() ) : key.compareTo(o);
+    if ( comp == 0 ) {
+      comp = ( this.hashCode() < o.hashCode() ) ? -1 : 1;
+    }
+    return comp;
+  }
+
+  /**
+   * Vergleicht das <code>ComparableObject</code> mit einem anderen. Wurde im
+   * {@linkplain #ComparableObject(K,V,boolean) Konstruktor} das <code>onlyObj</code>-Flag
+   * auf <code>true</code> gesetzt, wird an dieser Stelle nur das Objekt
+   * auf Gleichheit verglichen, ansonsten auch der Key.
+   * @param o ein anderes <code>ComparableObject</code>
+   */
+  public boolean equals(Object o) {
+    if ( !(o instanceof ComparableObject) )
+      return false;
+    ComparableObject c = (ComparableObject)o;
+    return this.obj.equals(c.getObject()) && (onlyObj || this.key.equals(c.getKey()));
+  }
+
+}

Modified: trunk/src/schmitzm/lang/DefaultComparator.java
===================================================================
--- trunk/src/schmitzm/lang/DefaultComparator.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/lang/DefaultComparator.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,69 +1,88 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.lang;
-
-import java.util.Comparator;
-
-/**
- * {@code Comparator} um beliebige Objekte ueber ihre {@code toString()}-Methode
- * zu vergleichen.
- * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class DefaultComparator implements Comparator<Object> {
-
-  /** Standard-Instanz dieses {@code Comparator}. */
-  public static final DefaultComparator DEFAULT = new DefaultComparator();
-
-  /**
-   * Erzeugt einen neuen {@code Comparator}.
-   */
-  public DefaultComparator() {
-  }
-
-  /**
-   * Fuehrt den Vergleich aus.
-   * @param obj1 ein Objekt
-   * @param obj2 ein anders Objekt
-   * @return ein negativer Wert fuer {@code obj1 < obj2}, 0 für {@code obj1 = obj2}
-   *         oder ein positiver Wert fuer {@code obj1 > obj2}
-   */
-  public int compare(Object obj1, Object obj2) {
-    if ( obj1 == null && obj2 == null )
-      return 0;
-    if ( obj1 == null )
-      return Integer.MAX_VALUE;
-    if ( obj2 == null )
-      return Integer.MIN_VALUE;
-    return obj1.toString().compareTo(obj2.toString());
-  }
-
-  /**
-   * Liefert einen {@link Comparator}, der die umgekehrte Reihenfolge eines
-   * {@link Comparator} definiert. {@code null}-Werte sind trotzdem groesser
-   * als alles andere und werden somit auch in der invertierten Reihenfolge
-   * hinten angehaengt.
-   * @param comparator ein Comparator
-   */
-  public static <T> Comparator<T> invert(final Comparator<T> comparator) {
-    return new Comparator<T>() {
-      public int compare(T obj1, T obj2) {
-        if ( obj1 == null && obj2 == null )
-          return 0;
-        if ( obj1 == null )
-          return Integer.MAX_VALUE;
-        if ( obj2 == null )
-          return Integer.MIN_VALUE;
-        return comparator.compare(obj2,obj1);
-      }
-    };
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.lang;
+
+import java.util.Comparator;
+
+/**
+ * {@code Comparator} um beliebige Objekte ueber ihre {@code toString()}-Methode
+ * zu vergleichen.
+ * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class DefaultComparator implements Comparator<Object> {
+
+  /** Standard-Instanz dieses {@code Comparator}. */
+  public static final DefaultComparator DEFAULT = new DefaultComparator();
+
+  /**
+   * Erzeugt einen neuen {@code Comparator}.
+   */
+  public DefaultComparator() {
+  }
+
+  /**
+   * Fuehrt den Vergleich aus.
+   * @param obj1 ein Objekt
+   * @param obj2 ein anders Objekt
+   * @return ein negativer Wert fuer {@code obj1 < obj2}, 0 für {@code obj1 = obj2}
+   *         oder ein positiver Wert fuer {@code obj1 > obj2}
+   */
+  public int compare(Object obj1, Object obj2) {
+    if ( obj1 == null && obj2 == null )
+      return 0;
+    if ( obj1 == null )
+      return Integer.MAX_VALUE;
+    if ( obj2 == null )
+      return Integer.MIN_VALUE;
+    return obj1.toString().compareTo(obj2.toString());
+  }
+
+  /**
+   * Liefert einen {@link Comparator}, der die umgekehrte Reihenfolge eines
+   * {@link Comparator} definiert. {@code null}-Werte sind trotzdem groesser
+   * als alles andere und werden somit auch in der invertierten Reihenfolge
+   * hinten angehaengt.
+   * @param comparator ein Comparator
+   */
+  public static <T> Comparator<T> invert(final Comparator<T> comparator) {
+    return new Comparator<T>() {
+      public int compare(T obj1, T obj2) {
+        if ( obj1 == null && obj2 == null )
+          return 0;
+        if ( obj1 == null )
+          return Integer.MAX_VALUE;
+        if ( obj2 == null )
+          return Integer.MIN_VALUE;
+        return comparator.compare(obj2,obj1);
+      }
+    };
+  }
+}

Modified: trunk/src/schmitzm/lang/DuplicateException.java
===================================================================
--- trunk/src/schmitzm/lang/DuplicateException.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/lang/DuplicateException.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,65 +1,83 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.lang;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+/**
+ * Diese Exception stellt einen Duplikat-Fehler dar.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class DuplicateException extends RuntimeException {
+  private Object currObj = null;
+  private Object duplObj = null;
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+  /**
+   * Erzeugt eine neue Exception
+   * @param mess    Fehlerbeschreibung
+   * @param currObj das bestehende Objekt
+   * @param duplObj das Duplikat, das den Fehler ausgeloest hat
+   */
+  public DuplicateException(String mess, Object currObj, Object duplObj) {
+    super(mess);
+    this.currObj = currObj;
+    this.duplObj = duplObj;
+  }
 
-package schmitzm.lang;
-
-/**
- * Diese Exception stellt einen Duplikat-Fehler dar.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class DuplicateException extends RuntimeException {
-  private Object currObj = null;
-  private Object duplObj = null;
-
-  /**
-   * Erzeugt eine neue Exception
-   * @param mess    Fehlerbeschreibung
-   * @param currObj das bestehende Objekt
-   * @param duplObj das Duplikat, das den Fehler ausgeloest hat
-   */
-  public DuplicateException(String mess, Object currObj, Object duplObj) {
-    super(mess);
-    this.currObj = currObj;
-    this.duplObj = duplObj;
-  }
-
-  /**
-   * Erzeugt eine neue Exception
-   * @param mess    Fehlerbeschreibung
-   */
-  public DuplicateException(String mess) {
-    this(mess, null, null);
-  }
-
-  /**
-   * Erzeugt eine neue Exception
-   */
-  public DuplicateException() {
-    this("", null, null);
-  }
-
-  /**
-   * Liefert das bestehende Objekt.
-   * @return Object
-   */
-  public Object getCurrentObject() {
-    return this.currObj;
-  }
-
-  /**
-   * Liefert das Objekt, das den Duplikatfehler ausgeloest hat.
-   */
-  public Object getDuplicateObject() {
-    return this.duplObj;
-  }
-
-}
+  /**
+   * Erzeugt eine neue Exception
+   * @param mess    Fehlerbeschreibung
+   */
+  public DuplicateException(String mess) {
+    this(mess, null, null);
+  }
+
+  /**
+   * Erzeugt eine neue Exception
+   */
+  public DuplicateException() {
+    this("", null, null);
+  }
+
+  /**
+   * Liefert das bestehende Objekt.
+   * @return Object
+   */
+  public Object getCurrentObject() {
+    return this.currObj;
+  }
+
+  /**
+   * Liefert das Objekt, das den Duplikatfehler ausgeloest hat.
+   */
+  public Object getDuplicateObject() {
+    return this.duplObj;
+  }
+
+}

Modified: trunk/src/schmitzm/lang/HashtableResourceBundle.java
===================================================================
--- trunk/src/schmitzm/lang/HashtableResourceBundle.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/lang/HashtableResourceBundle.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,99 +1,117 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.lang;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.lang;
-
 import java.util.Enumeration;
 import java.util.Hashtable;
 import java.util.ResourceBundle;
-
-/**
- * Diese Klasse stellt ein als {@link Hashtable} organisiertes
- * {@link ResourceBundle} dar. Sub-Klassen muessen lediglich noch die Methode
- * {@link #getContents()} implementieren, die den Inhalt des ResourceBundle
- * liefert. Aus diesem wird die Hash-Tabelle zusammengesetzt.<br>
- * Das ResourceBundle kann so eingestellt werden, dass es Fehler ignoriert.
- * Normalerweise wirft {@link ResourceBundle#getObject} eine Exception, wenn
- * zu einem Key kein Objekt (auch in keinem Parent-ResourceBundle) zu finden ist.
- * Ueber die Methode {@link #setErrorTolerant(boolean)} kann das
- * <code>HashtableResourceBundle</code> so eingestellt werden, dass ein
- * solcher Fehler vermieden wird, in dem statt <code>null</code> ein Dummy-String
- * von der Methode {@link #handleGetObject(String)} geliefert wird.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public abstract class HashtableResourceBundle extends ResourceBundle {
-  /** Speichert den Inhalt des {@link ResourceBundle}. */
-  protected Hashtable content = new Hashtable<String,Object>();
-
-  /** Speichert, ob das Fehlen einer angeforderten Ressource toleriert wird.<br>
-   *  Default: <code>false</code> */
-  protected static boolean errorTolerant = false;
-
-  /**
-   * Erzeugt ein neues ResourceBundle.
-   */
-  public HashtableResourceBundle() {
-    Object[][] res = getContents();
-    if ( res!=null ) {
-      content = new Hashtable<String, Object> (res.length);
-      for (int i = 0; i < res.length; i++) {
-        if (res[i].length < 2)
-          throw new UnsupportedOperationException("Return of HashtableResourceBundle.getContents() must be a two dimensional array!");
-        if ( !(res[i][0] instanceof String) )
-          throw new UnsupportedOperationException("HashtableResourceBundle.getContents() must contain Strings in first dimension!");
-        content.put(res[i][0], res[i][1]);
-      }
-    }
-  }
-
-  /**
-   * Liefert alle Keys zu denen eine Ressource hinterlegt ist.
-   */
-  public Enumeration<String> getKeys() {
-    return content.keys();
-  }
-
-  /**
-   * Stellt sie Toleranz des ResourceBundle bei fehlenden Ressourcen ein.
-   */
-  public static void setErrorTolerant(boolean tolerant) {
-    errorTolerant = tolerant;
-  }
-
-  /**
-   * Prueft, ob das ResourceBundle fehlertolerant auf fehlende Ressourcen
-   * reagiert.
-   */
-  public static boolean isErrorTolerant() {
-    return errorTolerant;
-  }
-
-  /**
-   * Liefert eine Ressource zu einem Key aus der Hash-Tabelle.
-   * @return <code>null</code> falls es den Key in der Hash-Tabelle nicht
-   *         gibt und die Fehlerroleranz abgeschaltet ist
-   */
-  protected Object handleGetObject(String key) {
-    Object obj = content.get(key);
-    // Wenn kein Objekt gefunden wurde, wuerde die Standard-Methode
-    // von ResourceBundle.getObject(String) eine Exception werfen
-    // Dies soll aber nicht der Fall sein, wenn das Bundle Fehler-Tolerant ist
-    if ( obj == null && parent == null && isErrorTolerant() )
-      obj = "'"+key+"'-Resource not found!";
-    return obj;
-  }
-
-  /**
-   * Liefert die (Key,Ressource)-Paerchen. Der Key <b>muss</b> ein String sein.
-   */
-  public abstract Object[][] getContents();
-}
+
+/**
+ * Diese Klasse stellt ein als {@link Hashtable} organisiertes
+ * {@link ResourceBundle} dar. Sub-Klassen muessen lediglich noch die Methode
+ * {@link #getContents()} implementieren, die den Inhalt des ResourceBundle
+ * liefert. Aus diesem wird die Hash-Tabelle zusammengesetzt.<br>
+ * Das ResourceBundle kann so eingestellt werden, dass es Fehler ignoriert.
+ * Normalerweise wirft {@link ResourceBundle#getObject} eine Exception, wenn
+ * zu einem Key kein Objekt (auch in keinem Parent-ResourceBundle) zu finden ist.
+ * Ueber die Methode {@link #setErrorTolerant(boolean)} kann das
+ * <code>HashtableResourceBundle</code> so eingestellt werden, dass ein
+ * solcher Fehler vermieden wird, in dem statt <code>null</code> ein Dummy-String
+ * von der Methode {@link #handleGetObject(String)} geliefert wird.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public abstract class HashtableResourceBundle extends ResourceBundle {
+  /** Speichert den Inhalt des {@link ResourceBundle}. */
+  protected Hashtable content = new Hashtable<String,Object>();
+
+  /** Speichert, ob das Fehlen einer angeforderten Ressource toleriert wird.<br>
+   *  Default: <code>false</code> */
+  protected static boolean errorTolerant = false;
+
+  /**
+   * Erzeugt ein neues ResourceBundle.
+   */
+  public HashtableResourceBundle() {
+    Object[][] res = getContents();
+    if ( res!=null ) {
+      content = new Hashtable<String, Object> (res.length);
+      for (int i = 0; i < res.length; i++) {
+        if (res[i].length < 2)
+          throw new UnsupportedOperationException("Return of HashtableResourceBundle.getContents() must be a two dimensional array!");
+        if ( !(res[i][0] instanceof String) )
+          throw new UnsupportedOperationException("HashtableResourceBundle.getContents() must contain Strings in first dimension!");
+        content.put(res[i][0], res[i][1]);
+      }
+    }
+  }
+
+  /**
+   * Liefert alle Keys zu denen eine Ressource hinterlegt ist.
+   */
+  public Enumeration<String> getKeys() {
+    return content.keys();
+  }
+
+  /**
+   * Stellt sie Toleranz des ResourceBundle bei fehlenden Ressourcen ein.
+   */
+  public static void setErrorTolerant(boolean tolerant) {
+    errorTolerant = tolerant;
+  }
+
+  /**
+   * Prueft, ob das ResourceBundle fehlertolerant auf fehlende Ressourcen
+   * reagiert.
+   */
+  public static boolean isErrorTolerant() {
+    return errorTolerant;
+  }
+
+  /**
+   * Liefert eine Ressource zu einem Key aus der Hash-Tabelle.
+   * @return <code>null</code> falls es den Key in der Hash-Tabelle nicht
+   *         gibt und die Fehlerroleranz abgeschaltet ist
+   */
+  protected Object handleGetObject(String key) {
+    Object obj = content.get(key);
+    // Wenn kein Objekt gefunden wurde, wuerde die Standard-Methode
+    // von ResourceBundle.getObject(String) eine Exception werfen
+    // Dies soll aber nicht der Fall sein, wenn das Bundle Fehler-Tolerant ist
+    if ( obj == null && parent == null && isErrorTolerant() )
+      obj = "'"+key+"'-Resource not found!";
+    return obj;
+  }
+
+  /**
+   * Liefert die (Key,Ressource)-Paerchen. Der Key <b>muss</b> ein String sein.
+   */
+  public abstract Object[][] getContents();
+}

Modified: trunk/src/schmitzm/lang/HashtableWithCollisionList.java
===================================================================
--- trunk/src/schmitzm/lang/HashtableWithCollisionList.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/lang/HashtableWithCollisionList.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,86 +1,104 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.lang;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+import java.util.Hashtable;
+import java.util.Vector;
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+/**
+ * Diese Klasse erweitert die normale Hash-Tabelle um Kollisionslisten.
+ * Pro Hashtable-Key koennen somit mehrere Werte gespeichert werden.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class HashtableWithCollisionList<K,V> extends Hashtable<K,Vector<V>> {
 
-package schmitzm.lang;
-
-import java.util.Hashtable;
-import java.util.Vector;
-
-/**
- * Diese Klasse erweitert die normale Hash-Tabelle um Kollisionslisten.
- * Pro Hashtable-Key koennen somit mehrere Werte gespeichert werden.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class HashtableWithCollisionList<K,V> extends Hashtable<K,Vector<V>> {
-
-  /**
-   * Erzeugt eine neue Hash-Tabelle.
-   */
-  public HashtableWithCollisionList() {
-    super();
-  }
-
-  /**
-   * Fuegt der Hash-Tabelle ein Objekt hinzu. Existiert bereits ein Element
-   * mit dem Key, wird dieses nicht entfernt, sondern die entsprechende
-   * Kollisionsliste erweitert.
-   * @param key   Der Hashtable-Key
-   * @param value Wert
-   */
-  public synchronized void add(K key, V value) {
-    // Wenn noch keine Kollisionsliste zu dem Key existiert, wird
-    // diese erzeugt
-    if ( !this.containsKey(key) )
-      super.put(key,new Vector<V>());
-    // In der Liste das Objekt hinzufuegen
-    ((Vector)this.get(key)).add(value);
-  }
-
-  /**
-   * Ersetzt eine komplette Kollisionsliste fuer einen Key.
-   * @param key   Der Hashtable-Key
-   * @param value Kollisionsliste
-   * @return immer <code>null</code>
-   */
-  public synchronized Vector<V> put(K key, Vector<V> value) {
-    super.put(key,value);
-    return null;
-  }
-
-  /**
-   * Entfernt eine komplette Kollisionsliste zu einem Key. Es werden nur die
-   * Element der Liste entfernt. Die Kollisionsliste selbst bleibt bestehen!
-   * @param key   Der Hashtable-Key
-   * @return immer <code>null</code>
-   */
-  public synchronized Vector<V> remove(Object key) {
-    Vector list = super.get(key);
-    if ( list!= null )
-      list.clear();
-    return null;
-  }
-
-  /**
-   * Entfernt ein objekt aus der Hash-Tabelle.
-   * @param key   Der Hashtable-Key
-   * @return Das entfernte Objekt oder <code>null</code> falls das Objekt
-   *         nicht in der Hash-Tabelle gespeichert war
-   */
-  public synchronized Object remove(Object key, Object value) {
-    Vector list = super.get(key);
-    if ( list == null )
-      return null;
-    list.remove(value);
-    return value;
-  }
-
-}
+  /**
+   * Erzeugt eine neue Hash-Tabelle.
+   */
+  public HashtableWithCollisionList() {
+    super();
+  }
+
+  /**
+   * Fuegt der Hash-Tabelle ein Objekt hinzu. Existiert bereits ein Element
+   * mit dem Key, wird dieses nicht entfernt, sondern die entsprechende
+   * Kollisionsliste erweitert.
+   * @param key   Der Hashtable-Key
+   * @param value Wert
+   */
+  public synchronized void add(K key, V value) {
+    // Wenn noch keine Kollisionsliste zu dem Key existiert, wird
+    // diese erzeugt
+    if ( !this.containsKey(key) )
+      super.put(key,new Vector<V>());
+    // In der Liste das Objekt hinzufuegen
+    ((Vector)this.get(key)).add(value);
+  }
+
+  /**
+   * Ersetzt eine komplette Kollisionsliste fuer einen Key.
+   * @param key   Der Hashtable-Key
+   * @param value Kollisionsliste
+   * @return immer <code>null</code>
+   */
+  public synchronized Vector<V> put(K key, Vector<V> value) {
+    super.put(key,value);
+    return null;
+  }
+
+  /**
+   * Entfernt eine komplette Kollisionsliste zu einem Key. Es werden nur die
+   * Element der Liste entfernt. Die Kollisionsliste selbst bleibt bestehen!
+   * @param key   Der Hashtable-Key
+   * @return immer <code>null</code>
+   */
+  public synchronized Vector<V> remove(Object key) {
+    Vector list = super.get(key);
+    if ( list!= null )
+      list.clear();
+    return null;
+  }
+
+  /**
+   * Entfernt ein objekt aus der Hash-Tabelle.
+   * @param key   Der Hashtable-Key
+   * @return Das entfernte Objekt oder <code>null</code> falls das Objekt
+   *         nicht in der Hash-Tabelle gespeichert war
+   */
+  public synchronized Object remove(Object key, Object value) {
+    Vector list = super.get(key);
+    if ( list == null )
+      return null;
+    list.remove(value);
+    return value;
+  }
+
+}

Modified: trunk/src/schmitzm/lang/Indent.java
===================================================================
--- trunk/src/schmitzm/lang/Indent.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/lang/Indent.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,99 +1,117 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.lang;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+/**
+ * Diese Klasse stellt eine Hilfsklasse fuer eingerueckte Texte dar.
+ * Mittels der Methoden {@link #push()} und {@link #pop()} wird die Einrueckung
+ * um ein feste Anzahl an Leerstellen erweitert bzw. reduziert.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class Indent {
+  private StringBuffer buffer = new StringBuffer();
+  private String       indent = null;
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+  /**
+   * Erzeugt eine neue Einrueckung fuer 2 Stellen.
+   */
+  public Indent() {
+    this(2);
+  }
 
-package schmitzm.lang;
-
-/**
- * Diese Klasse stellt eine Hilfsklasse fuer eingerueckte Texte dar.
- * Mittels der Methoden {@link #push()} und {@link #pop()} wird die Einrueckung
- * um ein feste Anzahl an Leerstellen erweitert bzw. reduziert.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class Indent {
-  private StringBuffer buffer = new StringBuffer();
-  private String       indent = null;
-
-  /**
-   * Erzeugt eine neue Einrueckung fuer 2 Stellen.
-   */
-  public Indent() {
-    this(2);
-  }
-
-  /**
-   * Erzeugt eine neue Einrueckung.
-   * @param len Anzahl der Stellen, um die eingerueckt wird.
-   */
-  public Indent(int len) {
-    indent = "";
-    for (int i=0; i<len; i++)
-      indent += "";
-  }
-
-  /**
-   * Loescht den Einrueck-Buffer.
-   */
-  public void clear() {
-    buffer = new StringBuffer();
-  }
-
-  /**
-   * Liefert die aktuelle Anzahl an Leerstellen, um die eingerueckt wird.
-   */
-  public int getLength() {
-    return buffer.length();
-  }
-
-  /**
-   * Liefert die Leerstellen, um die bei einem {@link #push()}-Aufruf
-   * eingerueckt wird.
-   */
-  public String getIndent() {
-    return indent;
-  }
-
-  /**
-   * Liefert die Anzahl an Leerstellen, um die bei einem {@link #push()}-Aufruf
-   * eingerueckt wird.
-   */
-  public int getIndentLength() {
-    return indent.length();
-  }
-
-
-  /**
-   * Erweitert die Einrueckung um die im Konstruktor angegebene Anzahl an
-   * Leerstellen.
-   * @see #getIndent()
-   * @see #getIndentLength()
-   */
-  public void push() {
-    buffer.append(indent);
-  }
-
-  /**
-   * Reduziert die Einrueckung um die im Konstruktor angegebene Anzahl an
-   * Leerstellen.
-   * @see #getIndent()
-   * @see #getIndentLength()
-   */
-  public void pop() {
-    buffer.delete( buffer.length()-indent.length(), buffer.length() );
-  }
-
-  /**
-   * Liefert die aktuelle Einrueckung als String.
-   */
-  public String toString() {
-    return buffer.toString();
-  }
-}
+  /**
+   * Erzeugt eine neue Einrueckung.
+   * @param len Anzahl der Stellen, um die eingerueckt wird.
+   */
+  public Indent(int len) {
+    indent = "";
+    for (int i=0; i<len; i++)
+      indent += "";
+  }
+
+  /**
+   * Loescht den Einrueck-Buffer.
+   */
+  public void clear() {
+    buffer = new StringBuffer();
+  }
+
+  /**
+   * Liefert die aktuelle Anzahl an Leerstellen, um die eingerueckt wird.
+   */
+  public int getLength() {
+    return buffer.length();
+  }
+
+  /**
+   * Liefert die Leerstellen, um die bei einem {@link #push()}-Aufruf
+   * eingerueckt wird.
+   */
+  public String getIndent() {
+    return indent;
+  }
+
+  /**
+   * Liefert die Anzahl an Leerstellen, um die bei einem {@link #push()}-Aufruf
+   * eingerueckt wird.
+   */
+  public int getIndentLength() {
+    return indent.length();
+  }
+
+
+  /**
+   * Erweitert die Einrueckung um die im Konstruktor angegebene Anzahl an
+   * Leerstellen.
+   * @see #getIndent()
+   * @see #getIndentLength()
+   */
+  public void push() {
+    buffer.append(indent);
+  }
+
+  /**
+   * Reduziert die Einrueckung um die im Konstruktor angegebene Anzahl an
+   * Leerstellen.
+   * @see #getIndent()
+   * @see #getIndentLength()
+   */
+  public void pop() {
+    buffer.delete( buffer.length()-indent.length(), buffer.length() );
+  }
+
+  /**
+   * Liefert die aktuelle Einrueckung als String.
+   */
+  public String toString() {
+    return buffer.toString();
+  }
+}

Modified: trunk/src/schmitzm/lang/LangUtil.java
===================================================================
--- trunk/src/schmitzm/lang/LangUtil.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/lang/LangUtil.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,898 +1,916 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.lang;
-
-import java.lang.reflect.Constructor;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.Locale;
-import java.util.TreeSet;
-import java.util.Vector;
-
-import net.jini.loader.pref.PreferredClassLoader;
-
-import org.apache.log4j.Category;
-import org.apache.log4j.Logger;
-
-/**
- * Diese Klasse stellt Hilfsfunktionen fuer Basisoperationen bereit.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class LangUtil {
-
-  /** {@link ResourceProvider}, der die Lokalisation fuer Komponenten
-   *  des Package {@code schmitzm.lang} zur Verfuegung stellt. Diese sind
-   *  in properties-Dateien unter {@code schmitzm.lang.resource.locales}
-   *  hinterlegt. */
-  public static ResourceProvider RESOURCE = new ResourceProvider( extendPackagePath(LangUtil.class,"resource.locales.LangResourceBundle"), Locale.ENGLISH );
-
-  /**
-   * Liefert den einfachen Namen einer Klasse (ohne Package) oder den
-   * String "null", falls das Objekt {@code null} ist
-   * @param object ein Objekt
-   * @param niemals {@code null}
-   */
-  public static String getSimpleClassName(Object object) {
-    if ( object == null )
-      return "null";
-    return object.getClass().getSimpleName();
-  }
-
-
-  /**
-   * Prueft, ob ein {@link Enum} ein spezielles Feld besitzt.
-   * @param enumClass enum typ
-   * @param fieldName feld name
-   */
-  public static boolean checkEnumValue(Class<? extends Enum> enumClass, String fieldName) {
-    try {
-      Enum.valueOf(enumClass, fieldName);
-      return true;
-    } catch (IllegalArgumentException err) {
-      return false;
-    }
-  }
-
-  /**
-   * Fuegt alle Elemente eines Arrays in einen {@link Vector} ein. Wird als Vector
-   * <code>null</code> angegeben, wird ein neuer Vector erzeugt.
-   * @param obj einzufuegende Objekte
-   * @param vec Vector in den die Elemente eingefuegt werden (kann <code>null</code>
-   *            sein)
-   * @return den Vector <code>vec</code> oder eine neue {@link Vector}-Instanz
-   */
-  public static Vector addObjectsToVector(Object[] obj, Vector vec) {
-    if ( vec == null )
-      vec = new Vector();
-    for (int i=0; i<obj.length; i++)
-      vec.add(obj[i]);
-    return vec;
-  }
-
-  /**
-   * Ersetzt alle Tabulator-Vorkommen in einem String durch Leerzeichen.
-   * @param source Quell-String
-   * @param tabLen Anzahl an Zeichen die ein Tabulator darstellt
-   */
-  public static String replaceTabulators(String source, int tabLen) {
-    String outString       = new String(source);
-    char[] maxSpacePattern = new char[tabLen];
-    Arrays.fill(maxSpacePattern,' ');
-
-    for(int pos; (pos=outString.indexOf('\t')) >= 0;) {
-      outString = outString.replaceFirst(
-        "\t",
-        String.valueOf(maxSpacePattern,0,tabLen-pos%tabLen)
-      );
-    }
-    return outString;
-  }
-
-  /**
-   * Haengt eine beliebige Anzahl von Strings hintereinander.
-   * @param str aneinanderzuhaengende Stings
-   */
-  public static String stringConcat(String... str) {
-    StringBuffer sb = new StringBuffer();
-    for (int i=0; str!=null && i<str.length; i++)
-      sb.append(str[i]);
-    return sb.toString();
-  }
-
-  /**
-   * Haengt eine beliebige Anzahl von Strings hintereinander und fuegt zwischen
-   * den Strings einen Trenner ein.
-   * @param sep Trenner
-   * @param str aneinanderzuhaengende Stings
-   */
-  public static String stringConcatWithSep(String sep, String... str) {
-    StringBuffer sb = new StringBuffer();
-    for (int i=0; str!=null && i<str.length; i++) {
-      if ( i>0 )
-        sb.append(sep);
-      sb.append(str[i]);
-    }
-    return sb.toString();
-  }
-
-  /**
-   * Erzeugt einen vorbelegten Array.
-   * @param count Groesse des Arrays
-   * @param value Wert mit dem die Elemente vorbelegt werden
-   */
-  public static int[] createArray(int count, int value) {
-    int[] array = new int[count];
-    java.util.Arrays.fill(array,value);
-    return array;
-  }
-
-  /**
-   * Erzeugt einen vorbelegten Array.
-   * @param count Groesse des Arrays
-   * @param value Wert mit dem die Elemente vorbelegt werden
-   */
-  public static long[] createArray(int count, long value) {
-    long[] array = new long[count];
-    java.util.Arrays.fill(array,value);
-    return array;
-  }
-
-  /**
-   * Erzeugt einen vorbelegten Array.
-   * @param count Groesse des Arrays
-   * @param value Wert mit dem die Elemente vorbelegt werden
-   */
-  public static float[] createArray(int count, float value) {
-    float[] array = new float[count];
-    java.util.Arrays.fill(array,value);
-    return array;
-  }
-
-  /**
-   * Erzeugt einen vorbelegten Array.
-   * @param count Groesse des Arrays
-   * @param value Wert mit dem die Elemente vorbelegt werden
-   */
-  public static double[] createArray(int count, double value) {
-    double[] array = new double[count];
-    java.util.Arrays.fill(array,value);
-    return array;
-  }
-
-  /**
-   * Erzeugt einen vorbelegten Array.
-   * @param count Groesse des Arrays
-   * @param value Wert mit dem die Elemente vorbelegt werden
-   */
-  public static String[] createArray(int count, String value) {
-    String[] array = new String[count];
-    java.util.Arrays.fill(array,value);
-    return array;
-  }
-
-  /**
-   * Erzeugt einen mehr-dimensionalen {@link Object}-Array.
-   * @param size Groesse der Array-Dimensionen
-   * @return einen {@code Object[]..[]}
-   */
-  public static Object createArray(int... size) {
-    switch ( size.length ) {
-      case  1: return new Object[size[0]];
-      case  2: return new Object[size[0]][size[1]];
-      case  3: return new Object[size[0]][size[1]][size[2]];
-      case  4: return new Object[size[0]][size[1]][size[2]][size[3]];
-      case  5: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]];
-      case  6: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]];
-      case  7: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]][size[6]];
-      case  8: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]][size[6]][size[7]];
-      case  9: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]][size[6]][size[7]][size[8]];
-      case 10: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]][size[6]][size[7]][size[8]][size[9]];
-      case 11: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]][size[6]][size[7]][size[8]][size[9]][size[10]];
-      case 12: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]][size[6]][size[7]][size[8]][size[9]][size[10]][size[11]];
-      case 13: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]][size[6]][size[7]][size[8]][size[9]][size[10]][size[11]][size[12]];
-      case 14: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]][size[6]][size[7]][size[8]][size[9]][size[10]][size[11]][size[12]][size[13]];
-      case 15: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]][size[6]][size[7]][size[8]][size[9]][size[10]][size[11]][size[12]][size[13]][size[14]];
-      case 16: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]][size[6]][size[7]][size[8]][size[9]][size[10]][size[11]][size[12]][size[13]][size[14]][size[15]];
-      case 17: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]][size[6]][size[7]][size[8]][size[9]][size[10]][size[11]][size[12]][size[13]][size[14]][size[15]][size[16]];
-      case 18: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]][size[6]][size[7]][size[8]][size[9]][size[10]][size[11]][size[12]][size[13]][size[14]][size[15]][size[16]][size[17]];
-      case 19: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]][size[6]][size[7]][size[8]][size[9]][size[10]][size[11]][size[12]][size[13]][size[14]][size[15]][size[16]][size[17]][size[18]];
-      case 20: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]][size[6]][size[7]][size[8]][size[9]][size[10]][size[11]][size[12]][size[13]][size[14]][size[15]][size[16]][size[17]][size[18]][size[19]];
-    }
-    throw new IllegalArgumentException("Dimension not supported: "+size.length);
-  }
-
-  /**
-   * Liefert die Dimension eines multi-dimensionalen {@link Object}-Array.<br>
-   * <b>Diese Methode funktioniert nur, wenn das Element 0 in jeder Dimension
-   * belegt ist!</b>
-   * @param array multi-dim. Array (Instanz von {@code Object[]..[]})
-   * @exception ArrayIndexOutOfBoundsException wenn das 0te Element in einer
-   *            Dimension mit {@code null} belegt ist
-   */
-  public static int getArrayDimension(Object array) {
-    int dim = 0;
-    try {
-      for (;; dim++) {
-        array = ((Object[])array)[0];
-      }
-    } catch (ClassCastException err) {
-    }
-    return dim;
-  }
-
-  /**
-   * Liefert die Groessen der einzelnen Dimensionen eines multi-dimensionalen
-   * {@link Object}-Array.<br>
-   * <b>Diese Methode funktioniert nur, wenn das Element 0 in jeder Dimension
-   * belegt ist!</b>
-   * @param array multi-dim. Array (Instanz von {@code Object[]..[]})
-   * @exception ArrayIndexOutOfBoundsException wenn das 0te Element in einer
-   *            Dimension mit {@code null} belegt ist
-   */
-  public static int[] getArrayLength(Object array) {
-    int[] dimSize = new int[ getArrayDimension(array) ];
-    for (int d=0; d<dimSize.length; d++) {
-      dimSize[d] = ((Object[])array).length;
-      array = ( (Object[]) array)[0];
-    }
-    return dimSize;
-  }
-
-  /**
-   * Liefert einen Wert aus einem multi-dimensionalen {@link Object}-Array.
-   * @param array multi-dim. Array (Instanz von {@code Object[]..[]})
-   * @param coord Koordinaten des Arrays
-   * @exception ArrayIndexOutOfBoundsException wenn eine fehlerhafte Koordinate
-   *            angegeben wird
-   */
-  public static Object getArrayValue(Object array, int... coord) {
-    for (int i=0; i<coord.length; i++)
-      array = ((Object[])array)[ coord[i] ];
-    return array;
-  }
-
-  /**
-   * Setzt einen Wert aus einem multi-dimensionalen {@link Object}-Array.
-   * @param array multi-dim. Array (Instanz von {@code Object[]..[]})
-   * @param value zu setzender Wert (Instanz von {@code Object[]..[]})
-   * @param coord Koordinaten des Arrays
-   * @exception ArrayIndexOutOfBoundsException wenn eine fehlerhafte Koordinate
-   *            angegeben wird
-   */
-  public static void setArrayValue(Object array, Object value, int... coord) {
-    for (int i=0; i<coord.length-1; i++)
-      array = ((Object[])array)[ coord[i] ];
-    ((Object[])array)[ coord[coord.length-1] ] = value;
-  }
-
-  /**
-   * Kopiert einen Array (aber nicht dessen Elemente). Darueberhinaus koennen
-   * (einige) Elemente direkt neu belegt werden. Ist das Flag {@code replNull}
-   * auf {@code false} gesetzt, werden {@code null}-Werte in {@code replElem}
-   * ignoriert. So ist es z.B. moeglich, nur das 4. und 5. Element im neuen
-   * Array neu zu belegen und die davor liegenden Elemente unangetastet zu lassen.
-   * @param source   zu kopierender Array
-   * @param replNull Bestimmt, ob {@code null}-Elemente von {@code replElem}
-   *                 im neuen Array gesetzt werden ({@code true}) oder nicht
-   * @param replElem Elemente (beginnend bei Index 0), die nach dem Kopieren
-   *                 im Array neu gesetzt werden
-   * @return Array von der Groesse {@code max(source.length, replElem.length)}
-   */
-  public static <T> T[] cloneArray(T[] source, boolean replNull, T... replElem) {
-    T[] newArray =  java.util.Arrays.copyOf(source, Math.max(source.length, replElem.length));
-    for (int i=0; i<replElem.length; i++)
-      if (replNull || replElem[i] != null)
-        newArray[i] = replElem[i];
-    return newArray;
-  }
-
-  /**
-   * Kopiert einen Array (aber nicht dessen Elemente). Darueberhinaus koennen
-   * (einige) Elemente direkt neu belegt werden.
-   * @param source   zu kopierender Array
-   * @param replElem Elemente (beginnend bei Index 0), die nach dem Kopieren
-   *                 im Array neu gesetzt werden
-   * @return Array von der Groesse {@code max(source.length, replElem.length)}
-   */
-  public static <T> T[] cloneArray(T[] source, T... replElem) {
-    return cloneArray(source,true,replElem);
-  }
-
-  /**
-   * Kopiert einen Array und belegt (einige) Elemente direkt neu.
-   * @param source   zu kopierender Array
-   * @param replElem Elemente (beginnend bei Index 0), die nach dem Kopieren
-   *                 im Array neu gesetzt werden
-   * @return Array von der Groesse {@code max(source.length, replElem.length)}
-   */
-  public static long[] cloneArray(long[] source, long... replElem) {
-    long[] newArray =  java.util.Arrays.copyOf(source, Math.max(source.length, replElem.length));
-    for (int i=0; i<replElem.length; i++)
-      newArray[i] = replElem[i];
-    return newArray;
-  }
-
-  /**
-   * Kopiert einen Array und belegt (einige) Elemente direkt neu.
-   * @param source   zu kopierender Array
-   * @param replElem Elemente (beginnend bei Index 0), die nach dem Kopieren
-   *                 im Array neu gesetzt werden
-   * @return Array von der Groesse {@code max(source.length, replElem.length)}
-   */
-  public static int[] cloneArray(int[] source, int... replElem) {
-    int[] newArray =  java.util.Arrays.copyOf(source, Math.max(source.length, replElem.length));
-    for (int i=0; i<replElem.length; i++)
-      newArray[i] = replElem[i];
-    return newArray;
-  }
-
-  /**
-   * Kopiert einen Array und belegt (einige) Elemente direkt neu.
-   * @param source   zu kopierender Array
-   * @param replElem Elemente (beginnend bei Index 0), die nach dem Kopieren
-   *                 im Array neu gesetzt werden
-   * @return Array von der Groesse {@code max(source.length, replElem.length)}
-   */
-  public static short[] cloneArray(short[] source, short... replElem) {
-    short[] newArray =  java.util.Arrays.copyOf(source, Math.max(source.length, replElem.length));
-    for (int i=0; i<replElem.length; i++)
-      newArray[i] = replElem[i];
-    return newArray;
-  }
-
-  /**
-   * Kopiert einen Array und belegt (einige) Elemente direkt neu.
-   * @param source   zu kopierender Array
-   * @param replElem Elemente (beginnend bei Index 0), die nach dem Kopieren
-   *                 im Array neu gesetzt werden
-   * @return Array von der Groesse {@code max(source.length, replElem.length)}
-   */
-  public static byte[] cloneArray(byte[] source, byte... replElem) {
-    byte[] newArray =  java.util.Arrays.copyOf(source, Math.max(source.length, replElem.length));
-    for (int i=0; i<replElem.length; i++)
-      newArray[i] = replElem[i];
-    return newArray;
-  }
-
-  /**
-   * Kopiert einen Array und belegt (einige) Elemente direkt neu.
-   * @param source   zu kopierender Array
-   * @param replElem Elemente (beginnend bei Index 0), die nach dem Kopieren
-   *                 im Array neu gesetzt werden
-   * @return Array von der Groesse {@code max(source.length, replElem.length)}
-   */
-  public static double[] cloneArray(double[] source, double... replElem) {
-    double[] newArray =  java.util.Arrays.copyOf(source, Math.max(source.length, replElem.length));
-    for (int i=0; i<replElem.length; i++)
-      newArray[i] = replElem[i];
-    return newArray;
-  }
-
-  /**
-   * Kopiert einen Array und belegt (einige) Elemente direkt neu.
-   * @param source   zu kopierender Array
-   * @param replElem Elemente (beginnend bei Index 0), die nach dem Kopieren
-   *                 im Array neu gesetzt werden
-   * @return Array von der Groesse {@code max(source.length, replElem.length)}
-   */
-  public static float[] cloneArray(float[] source, float... replElem) {
-    float[] newArray =  java.util.Arrays.copyOf(source, Math.max(source.length, replElem.length));
-    for (int i=0; i<replElem.length; i++)
-      newArray[i] = replElem[i];
-    return newArray;
-  }
-
-  /**
-   * Kopiert einen Array und belegt (einige) Elemente direkt neu.
-   * @param source   zu kopierender Array
-   * @param replElem Elemente (beginnend bei Index 0), die nach dem Kopieren
-   *                 im Array neu gesetzt werden
-   * @return Array von der Groesse {@code max(source.length, replElem.length)}
-   */
-  public static boolean[] cloneArray(boolean[] source, boolean... replElem) {
-    boolean[] newArray =  java.util.Arrays.copyOf(source, Math.max(source.length, replElem.length));
-    for (int i=0; i<replElem.length; i++)
-      newArray[i] = replElem[i];
-    return newArray;
-  }
-
-  /**
-   * Kopiert einen Array und belegt (einige) Elemente direkt neu.
-   * @param source   zu kopierender Array
-   * @param replElem Elemente (beginnend bei Index 0), die nach dem Kopieren
-   *                 im Array neu gesetzt werden
-   * @return Array von der Groesse {@code max(source.length, replElem.length)}
-   */
-  public static char[] cloneArray(char[] source, char... replElem) {
-    char[] newArray =  java.util.Arrays.copyOf(source, Math.max(source.length, replElem.length));
-    for (int i=0; i<replElem.length; i++)
-      newArray[i] = replElem[i];
-    return newArray;
-  }
-
-  /**
-   * Erweitert einen Array.
-   * @param source   zu kopierender Array
-   * @param newElem  Elemente, die an das Ende des Arrays angehaengt werden
-   * @return Array von der Groesse {@code source.length + newElem.length}
-   */
-  public static <T> T[] extendArray(T[] source, T... newElem) {
-    T[] newArray =  java.util.Arrays.copyOf(source, source.length+newElem.length);
-    for (int i=0; i<newElem.length; i++)
-      newArray[source.length+i] = newElem[i];
-    return newArray;
-  }
-
-  /**
-   * Erweitert einen Array.
-   * @param source   zu kopierender Array
-   * @param newElem  Elemente, die an das Ende des Arrays angehaengt werden
-   * @return Array von der Groesse {@code source.length + newElem.length}
-   */
-  public static long[] extendArray(long[] source, long... newElem) {
-    long[] newArray =  java.util.Arrays.copyOf(source, source.length+newElem.length);
-    for (int i=0; i<newElem.length; i++)
-      newArray[source.length+i] = newElem[i];
-    return newArray;
-  }
-
-  /**
-   * Erweitert einen Array.
-   * @param source   zu kopierender Array
-   * @param newElem  Elemente, die an das Ende des Arrays angehaengt werden
-   * @return Array von der Groesse {@code source.length + newElem.length}
-   */
-  public static int[] extendArray(int[] source, int... newElem) {
-    int[] newArray = java.util.Arrays.copyOf(source, source.length+newElem.length);
-    for (int i=0; i<newElem.length; i++)
-      newArray[source.length+i] = newElem[i];
-    return newArray;
-  }
-
-  /**
-   * Erweitert einen Array.
-   * @param source   zu kopierender Array
-   * @param newElem  Elemente, die an das Ende des Arrays angehaengt werden
-   * @return Array von der Groesse {@code source.length + newElem.length}
-   */
-  public static short[] extendArray(short[] source, short... newElem) {
-    short[] newArray =  java.util.Arrays.copyOf(source, source.length+newElem.length);
-    for (int i=0; i<newElem.length; i++)
-      newArray[source.length+i] = newElem[i];
-    return newArray;
-  }
-
-  /**
-   * Erweitert einen Array.
-   * @param source   zu kopierender Array
-   * @param newElem  Elemente, die an das Ende des Arrays angehaengt werden
-   * @return Array von der Groesse {@code source.length + newElem.length}
-   */
-  public static byte[] extendArray(byte[] source, byte... newElem) {
-    byte[] newArray =  java.util.Arrays.copyOf(source, source.length+newElem.length);
-    for (int i=0; i<newElem.length; i++)
-      newArray[source.length+i] = newElem[i];
-    return newArray;
-  }
-
-  /**
-   * Erweitert einen Array.
-   * @param source   zu kopierender Array
-   * @param newElem  Elemente, die an das Ende des Arrays angehaengt werden
-   * @return Array von der Groesse {@code source.length + newElem.length}
-   */
-  public static double[] extendArray(double[] source, double... newElem) {
-    double[] newArray =  java.util.Arrays.copyOf(source, source.length+newElem.length);
-    for (int i=0; i<newElem.length; i++)
-      newArray[source.length+i] = newElem[i];
-    return newArray;
-  }
-
-  /**
-   * Erweitert einen Array.
-   * @param source   zu kopierender Array
-   * @param newElem  Elemente, die an das Ende des Arrays angehaengt werden
-   * @return Array von der Groesse {@code source.length + newElem.length}
-   */
-  public static float[] extendArray(float[] source, float... newElem) {
-    float[] newArray =  java.util.Arrays.copyOf(source, source.length+newElem.length);
-    for (int i=0; i<newElem.length; i++)
-      newArray[source.length+i] = newElem[i];
-    return newArray;
-  }
-
-  /**
-   * Erweitert einen Array.
-   * @param source   zu kopierender Array
-   * @param newElem  Elemente, die an das Ende des Arrays angehaengt werden
-   * @return Array von der Groesse {@code source.length + newElem.length}
-   */
-  public static boolean[] extendArray(boolean[] source, boolean... newElem) {
-    boolean[] newArray =  java.util.Arrays.copyOf(source, source.length+newElem.length);
-    for (int i=0; i<newElem.length; i++)
-      newArray[source.length+i] = newElem[i];
-    return newArray;
-  }
-
-  /**
-   * Erweitert einen Array.
-   * @param source   zu kopierender Array
-   * @param newElem  Elemente, die an das Ende des Arrays angehaengt werden
-   * @return Array von der Groesse {@code source.length + newElem.length}
-   */
-  public static char[] extendArray(char[] source, char... newElem) {
-    char[] newArray =  java.util.Arrays.copyOf(source, source.length+newElem.length);
-    for (int i=0; i<newElem.length; i++)
-      newArray[source.length+i] = newElem[i];
-    return newArray;
-  }
-
-  /**
-   * Liefert die Klassen-Namen zu einem Array von Klassen.
-   * @param clazz  Klassen
-   * @param simple gibt an, ob der einfache Klassenname ({@code true}) oder der
-   *               komplette Klassenname inkl. Paketname ({@code false})
-   *               zurueckgegeben wird.
-   */
-  public static String[] getClassNames(Class[] clazz, boolean simple) {
-    String[] className = new String[clazz.length];
-    for (int i=0; i<className.length; i++)
-      className[i] = simple ? clazz[i].getSimpleName() : clazz[i].getName();
-    return className;
-  }
-
-  /**
-   * Ruft die Java Garbage Collection auf.
-   * @return Anzahl an Bytes, die durch den Aufruf der Garbage Collection
-   *         freigegeben wurden
-   * @see Runtime#gc()
-   * @see Runtime#freeMemory()
-   */
-  public static long gc() {
-    Runtime runtime = Runtime.getRuntime();
-    long prevFreeMem = runtime.freeMemory();
-    runtime.gc();
-    return runtime.freeMemory() - prevFreeMem;
-  }
-
-  /**
-   * Ruft die Java Garbage Collection solange auf, bis kein Speicher mehr
-   * freigegeben werden kann.
-   * @return Gesamt-Anzahl an Bytes, die durch die Aufrufe der Garbage Collection
-   *         freigegeben wurden
-   * @see #gc()
-   */
-  public static long gcTotal() {
-    long totalFreedMem = 0;
-    for ( long freedMem=0; (freedMem = gc()) > 0; )
-     totalFreedMem += freedMem;
-    return totalFreedMem;
-  }
-
-  /**
-   * Erzeugt einen neuen {@link URLClassLoader}, der vom
-   * {@linkplain ClassLoader#getSystemClassLoader() System-ClassLoaders}
-   * abgeleitet ist.
-   * @param searchPath Pfade, in denen der ClassLoader nach Klassen sucht
-   */
-  public static ClassLoader createClassLoader(URL[] searchPath) {
-    return URLClassLoader.newInstance( searchPath, ClassLoader.getSystemClassLoader() );
-  }
-
-  /**
-   * Erzeugt einen neuen {@link URLClassLoader}, der vom
-   * {@linkplain ClassLoader#getSystemClassLoader() System-ClassLoaders}
-   * abgeleitet ist.
-   * @param searchPath Pfad, in denm der ClassLoader nach Klassen sucht
-   */
-  public static ClassLoader createClassLoader(URL searchPath) {
-    return createClassLoader( new URL[] {searchPath} );
-  }
-
-  /**
-   * Laed eine Klasse. Ggf. wird hierfuer ein neuer {@link ClassLoader}
-   * erzeugt.
-   * @param clazz      Klassenname (inkl. Paket)
-   * @param searchPath Pfade, in denen der ClassLoader nach Klassen sucht
-   *                   (wenn <code>null</code>, wird der
-   *                   {@linkplain ClassLoader#getSystemClassLoader() System-ClassLoader}
-   *                   zum Laden der Klasse verwendet)
-   */
-  public static Class loadClass(String clazz, URL[] searchPath) throws ClassNotFoundException {
-    if ( searchPath == null )
-      return Class.forName(clazz);
-    return createClassLoader(searchPath).loadClass(clazz);
-  }
-
-  /**
-   * Laed eine Klasse. Ggf. wird hierfuer ein neuer {@link ClassLoader}
-   * erzeugt.
-   * @param clazz      Klassenname (inkl. Paket)
-   * @param searchPath Pfad, in dem der ClassLoader nach Klassen sucht
-   *                   (wenn <code>null</code>, wird der
-   *                   {@linkplain ClassLoader#getSystemClassLoader() System-ClassLoader}
-   *                   zum Laden der Klasse verwendet)
-   */
-  public static Class loadClass(String clazz, URL searchPath) throws ClassNotFoundException {
-    if ( searchPath == null )
-      return Class.forName(clazz);
-    return createClassLoader(searchPath).loadClass(clazz);
-  }
-
-  /**
-	 *
-	 * Laed eine Klasse derart das Klassen im Cache ignoriert werden. Dazu ist es erforderlich
-	 * das unter dem Parameter <code>searchPath</code> eine Verzeichnis "META-INF" vorhanden ist.
-	 * Darin muss eine Datei "PREFERRED.LIST" sein. Wie genau diese Datei aufgebaut sein muss, lässt
-	 * sich in der Dokumentation des {@link PreferredClassLoader PreferredClassLoaders} nachlesen.
-	 *
-	 * @param classname  Klassenname (inkl. Paket)
-	 * @param searchPath Pfad, in dem der ClassLoader nach Klassen sucht
-	 *                   (wenn <code>null</code>, wird der System-Klassenpfad
-	 *                   {@linkplain ClassLoader#getSystemResource(String) ClassLoader.getSystemResource("")}
-	 *                   zum Laden der Klasse verwendet)
-	 * @throws ClassNotFoundException
-	 * @see PreferredClassLoader
-	 *
-	 *  @author Dominik Appl
-	 */
-	public static Class loadPreferredClass(String classname, URL searchPath)
-			throws ClassNotFoundException {
-                if ( searchPath == null )
-                  // System-Klassenpfad verwenden
-                  searchPath = ClassLoader.getSystemResource("");
-		PreferredClassLoader classLoader = new PreferredClassLoader(
-				new URL[]{searchPath}, Thread.currentThread()
-						.getContextClassLoader(), null, false);
-		Class loadedClass = classLoader.loadClass(classname);
-		if (loadedClass == null)
-			return Class.forName(classname);
-
-		return loadedClass;
-	}
-
-  /**
-   * Laed eine Klasse neu und erzeugt eine Objekt-Instanz. Als Suchpfad fuer
-   * die Klasse der System-Klassenpfad
-   * {@linkplain ClassLoader#getSystemResource(String) ClassLoader.getSystemResource("")}
-   * verwendet.
-   * @param classname Klassenname (inkl. Paket)
-   * @param param Parameter fuer den Konstruktor-Aufruf
-   * @exception RuntimeException falls irgendein Fehler auftritt
-   */
-  public static Object loadPreferredObject(String classname, Object... param) {
-    return loadPreferredObject(classname,null,param);
-  }
-
-  /**
-   * Laed eine Klasse neu und erzeugt eine Objekt-Instanz.
-   * @param classname Klassenname (inkl. Paket)
-   * @param searchPath Pfad, in dem der ClassLoader nach Klassen sucht
-   *                   (wenn <code>null</code>, wird der System-Klassenpfad
-   *                   {@linkplain ClassLoader#getSystemResource(String) ClassLoader.getSystemResource("")}
-   *                   zum Laden der Klasse verwendet)
-   * @param param Parameter fuer den Konstruktor-Aufruf
-   * @exception RuntimeException falls irgendein Fehler auftritt
-   */
-  public static Object loadPreferredObject(String classname, URL searchPath, Object... param) {
-    try {
-      // Klasse laden
-      Class clazz = loadPreferredClass(classname,searchPath);
-//      // Klassen der Konstruktor-Parameter ermitteln
-//      Class[] paramClass = new Class[ param.length ];
-//      for (int i=0; i<paramClass.length; i++)
-//        paramClass[i] = param[i].getClass();
-//      // Konstruktor fuer Parameter ermitteln (erfordert exakes Matching
-//      // zwischen den Klassen der uebergebenen Parameter und der Klassen
-//      // der Konstruktor-Parameter!)
-//      Constructor constructor = clazz.getConstructor(paramClass);
-      // Konstruktor fuer Parameter ausprobieren
-      for ( Constructor constructor : clazz.getConstructors() )
-        try {
-          return constructor.newInstance(param);
-        } catch (IllegalArgumentException err) {
-        }
-        // kein passender Konstruktor gefunden
-        throw new UnsupportedOperationException("No matching constructor found...");
-    } catch (Exception err) {
-      throw new RuntimeException(err);
-    }
-  }
-
-
-  /**
-   * Liefert das Package einer Klasse erweitert um einen relativen Pfad
-   * in Punkt-Notation.
-   * @param clazz eine Klasse
-   * @param pathExt Erweiterung des Pfads
-   */
-  public static String extendPackagePath(Class clazz, String pathExt) {
-    String packagePath = clazz.getPackage().getName();
-    if ( pathExt != null && !pathExt.trim().equals("") )
-      packagePath += "." + pathExt;
-    return packagePath;
-  }
-
-
-  /**
-   * Prueft einen Identifier auf Korrektheit.
-   * @param identifier Identifier
-   * @exception IllegalArgumentException falls der Identifier nicht-erlaubte
-   *            Zeichen enthaelt
-   * @see Character#isJavaIdentifierStart(char)
-   * @see Character#isJavaIdentifierPart(char)
-   */
-  public static void checkIdentifierAndError(String identifier) {
-    if ( !Character.isJavaIdentifierStart( identifier.charAt(0) ) )
-      throw new IllegalArgumentException("Illegal first character '"+identifier.charAt(0)+"'");
-    for (int i=1; i<identifier.length(); i++) {
-      char c = identifier.charAt(i);
-      if ( !Character.isJavaIdentifierPart(c) )
-        throw new IllegalArgumentException("Illegal inner character '"+c+"'");
-    }
-  }
-
-  /**
-   * Prueft einen Identifier auf Korrektheit.
-   * @param identifier Identifier
-   * @see #checkIdentifierAndError(String)
-   */
-  public static boolean checkIdentifier(String identifier) {
-    try {
-      checkIdentifierAndError(identifier);
-      return true;
-    } catch ( Exception err ) {
-      return false;
-    }
-  }
-
-  /**
-   * Sortiert einen Array aus beliebigen Objekten nach der natuerlichen
-   * Sortierung ihrer {@code toString()}-Werte.
-   * @param objects Objekte
-   */
-  public static void sort(Object[] objects) {
-    Arrays.sort( objects, new Comparator<Object>() {
-      public int compare(Object c1, Object c2) {
-        return c1.toString().compareTo(c2.toString());
-      }
-    });
-  }
-
-  /**
-   * Rundet einen Wert auf Nach- oder Vorkommastellen.
-   * @param value Wert
-   * @param digits Anzahl an Nachkommastellen (negative Werte runden auf
-   *               Vorkommastellen, also 10er-, 100er-, usw. Stelle)
-   * @param mode Modus für das Runden (0 = normal Runden, 1 = Aufrunden, -1 = Abrunden;
-   *             wenn nicht angegeben, wird normal gerundet)
-   */
-  public static double round(double value, int digits, int... mode) {
-    int roundMode = 0; // Default: Normal-Runden
-    if ( mode.length > 0 )
-      roundMode = mode[0];
-
-    // 10er-Potenz fuer Nachkommestellen bilden um vor dem Runden
-    // die Nachkommastellen "vor das Komma" zu schieben
-    double digitsFactor = Math.pow(10, digits);
-    value = value * digitsFactor;
-    // Runden
-    if ( roundMode < 0 )
-      value = Math.floor(value);
-    else if ( roundMode > 0 )
-      value = Math.ceil(value);
-    else
-      value = Math.round(value);
-
-    // Nachkommastellen wieder hinter das Komma schieben
-    return value / digitsFactor;
-  }
-
-  /**
-   * Rundet alle Werte einer {@link Collection} auf Nach- oder Vorkommastellen.<br>
-   * <b>Achtung:</b><br>
-   * Es wird eine neue {@link Collection} des gleichen Typs erzeugt und die
-   * gerundeten Werte darin in der Reihenfolge eingefuegt, wie sie von
-   * {@link Collection#iterator()} geliefert werden! Unter umstaenden kann
-   * die urspruengliche Sortierung verloren gehen! Diese Methode sollte also
-   * im Zweifelsfall nur auf automatisch sortierte {@link Collection Collections}
-   * angewandt werden (z.B. {@link TreeSet}).
-   * @param values Werte
-   * @param digits Anzahl an Nachkommastellen (negative Werte runden auf
-   *               Vorkommastellen, also 10er-, 100er-, usw. Stelle)
-   * @param mode Modus für das Runden (0 = normal Runden, 1 = Aufrunden, -1 = Abrunden;
-   *             wenn nicht angegeben, wird normal gerundet)
-   */
-  public static Collection<Number> round(Collection<Number> values, int digits, int... mode) {
-    try {
-      Collection<Number> newCollection = values.getClass().newInstance();
-      for (Number value : values) {
-        newCollection.add( round(value.doubleValue(),digits,mode) );
-      }
-      return newCollection;
-    } catch (Exception err) {
-      throw new IllegalArgumentException("Can not handle collection: "+getSimpleClassName(values),err);
-    }
-  }
-
-  /**
-   * Erzeugt einen Log4j-Logger fuer ein Objekt. Als Identifier fuer den Logger
-   * wird der Klassenname des Objekts verwendet.
-   * @param object ein Objekt
-   * @return Logger mit dem Namen "NULL", falls das uebergebene Objekt {@code null}
-   *         ist
-   */
-  public static Logger createLogger(Object object) {
-    if ( object == null )
-      return Logger.getLogger("");
-    if ( object instanceof Class )
-      return Logger.getLogger( ((Class)object).getName() );
-    return Logger.getLogger( object.getClass().getName() );
-  }
-
-  /**
-   * Erzeugt einen Error- und einen Debug-Eintrag in einem Logger. Der Error-Eintrag
-   * erhaelt nur die Meldung, der Debug-Eintrag auch die detaillierten Informationen
-   * des Fehlers.
-   * @param logger ein Logger
-   * @param mess   Fehlermeldung (wenn {@code null} wird die Message des Fehlers ausgegeben)
-   * @param err    ein Fehler
-   */
-  public static void logDebugError(Category logger, Object mess, Throwable err) {
-    if ( mess == null )
-      mess = err.getClass().getName()+": "+err.getMessage();
-    logger.error(mess);
-    logger.debug(mess,err);
-  }
-
-  /**
-   * Erzeugt einen Error- und einen Debug-Eintrag in einem Logger. Der Error-Eintrag
-   * erhaelt nur die Meldung, der Debug-Eintrag auch die detaillierten Informationen
-   * des Fehlers.
-   * @param logger ein Logger
-   * @param err    ein Fehler
-   */
-  public static void logDebugError(Category logger, Throwable err) {
-    logDebugError(logger,null,err);
-  }
-
-  /**
-   * Erzeugt einen Warn- und einen Debug-Eintrag in einem Logger. Der Warn-Eintrag
-   * erhaelt nur die Meldung, der Debug-Eintrag auch die detaillierten Informationen
-   * des Fehlers.
-   * @param logger ein Logger
-   * @param mess   Fehlermeldung (wenn {@code null} wird die Message des Fehlers ausgegeben)
-   * @param err    ein Fehler
-   */
-  public static void logDebugWarn(Category logger, Object mess, Throwable err) {
-    if ( mess == null )
-      mess = err.getClass().getName()+": "+err.getMessage();
-    logger.warn(mess);
-    logger.debug(mess,err);
-  }
-
-  /**
-   * Erzeugt einen Warn- und einen Debug-Eintrag in einem Logger. Der Warn-Eintrag
-   * erhaelt nur die Meldung, der Debug-Eintrag auch die detaillierten Informationen
-   * des Fehlers.
-   * @param logger ein Logger
-   * @param err    ein Fehler
-   */
-  public static void logDebugWarn(Category logger, Throwable err) {
-    logDebugWarn(logger,null,err);
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.lang;
+
+import java.lang.reflect.Constructor;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Locale;
+import java.util.TreeSet;
+import java.util.Vector;
+
+import net.jini.loader.pref.PreferredClassLoader;
+
+import org.apache.log4j.Category;
+import org.apache.log4j.Logger;
+
+/**
+ * Diese Klasse stellt Hilfsfunktionen fuer Basisoperationen bereit.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class LangUtil {
+
+  /** {@link ResourceProvider}, der die Lokalisation fuer Komponenten
+   *  des Package {@code schmitzm.lang} zur Verfuegung stellt. Diese sind
+   *  in properties-Dateien unter {@code schmitzm.lang.resource.locales}
+   *  hinterlegt. */
+  public static ResourceProvider RESOURCE = new ResourceProvider( extendPackagePath(LangUtil.class,"resource.locales.LangResourceBundle"), Locale.ENGLISH );
+
+  /**
+   * Liefert den einfachen Namen einer Klasse (ohne Package) oder den
+   * String "null", falls das Objekt {@code null} ist
+   * @param object ein Objekt
+   * @param niemals {@code null}
+   */
+  public static String getSimpleClassName(Object object) {
+    if ( object == null )
+      return "null";
+    return object.getClass().getSimpleName();
+  }
+
+
+  /**
+   * Prueft, ob ein {@link Enum} ein spezielles Feld besitzt.
+   * @param enumClass enum typ
+   * @param fieldName feld name
+   */
+  public static boolean checkEnumValue(Class<? extends Enum> enumClass, String fieldName) {
+    try {
+      Enum.valueOf(enumClass, fieldName);
+      return true;
+    } catch (IllegalArgumentException err) {
+      return false;
+    }
+  }
+
+  /**
+   * Fuegt alle Elemente eines Arrays in einen {@link Vector} ein. Wird als Vector
+   * <code>null</code> angegeben, wird ein neuer Vector erzeugt.
+   * @param obj einzufuegende Objekte
+   * @param vec Vector in den die Elemente eingefuegt werden (kann <code>null</code>
+   *            sein)
+   * @return den Vector <code>vec</code> oder eine neue {@link Vector}-Instanz
+   */
+  public static Vector addObjectsToVector(Object[] obj, Vector vec) {
+    if ( vec == null )
+      vec = new Vector();
+    for (int i=0; i<obj.length; i++)
+      vec.add(obj[i]);
+    return vec;
+  }
+
+  /**
+   * Ersetzt alle Tabulator-Vorkommen in einem String durch Leerzeichen.
+   * @param source Quell-String
+   * @param tabLen Anzahl an Zeichen die ein Tabulator darstellt
+   */
+  public static String replaceTabulators(String source, int tabLen) {
+    String outString       = new String(source);
+    char[] maxSpacePattern = new char[tabLen];
+    Arrays.fill(maxSpacePattern,' ');
+
+    for(int pos; (pos=outString.indexOf('\t')) >= 0;) {
+      outString = outString.replaceFirst(
+        "\t",
+        String.valueOf(maxSpacePattern,0,tabLen-pos%tabLen)
+      );
+    }
+    return outString;
+  }
+
+  /**
+   * Haengt eine beliebige Anzahl von Strings hintereinander.
+   * @param str aneinanderzuhaengende Stings
+   */
+  public static String stringConcat(String... str) {
+    StringBuffer sb = new StringBuffer();
+    for (int i=0; str!=null && i<str.length; i++)
+      sb.append(str[i]);
+    return sb.toString();
+  }
+
+  /**
+   * Haengt eine beliebige Anzahl von Strings hintereinander und fuegt zwischen
+   * den Strings einen Trenner ein.
+   * @param sep Trenner
+   * @param str aneinanderzuhaengende Stings
+   */
+  public static String stringConcatWithSep(String sep, String... str) {
+    StringBuffer sb = new StringBuffer();
+    for (int i=0; str!=null && i<str.length; i++) {
+      if ( i>0 )
+        sb.append(sep);
+      sb.append(str[i]);
+    }
+    return sb.toString();
+  }
+
+  /**
+   * Erzeugt einen vorbelegten Array.
+   * @param count Groesse des Arrays
+   * @param value Wert mit dem die Elemente vorbelegt werden
+   */
+  public static int[] createArray(int count, int value) {
+    int[] array = new int[count];
+    java.util.Arrays.fill(array,value);
+    return array;
+  }
+
+  /**
+   * Erzeugt einen vorbelegten Array.
+   * @param count Groesse des Arrays
+   * @param value Wert mit dem die Elemente vorbelegt werden
+   */
+  public static long[] createArray(int count, long value) {
+    long[] array = new long[count];
+    java.util.Arrays.fill(array,value);
+    return array;
+  }
+
+  /**
+   * Erzeugt einen vorbelegten Array.
+   * @param count Groesse des Arrays
+   * @param value Wert mit dem die Elemente vorbelegt werden
+   */
+  public static float[] createArray(int count, float value) {
+    float[] array = new float[count];
+    java.util.Arrays.fill(array,value);
+    return array;
+  }
+
+  /**
+   * Erzeugt einen vorbelegten Array.
+   * @param count Groesse des Arrays
+   * @param value Wert mit dem die Elemente vorbelegt werden
+   */
+  public static double[] createArray(int count, double value) {
+    double[] array = new double[count];
+    java.util.Arrays.fill(array,value);
+    return array;
+  }
+
+  /**
+   * Erzeugt einen vorbelegten Array.
+   * @param count Groesse des Arrays
+   * @param value Wert mit dem die Elemente vorbelegt werden
+   */
+  public static String[] createArray(int count, String value) {
+    String[] array = new String[count];
+    java.util.Arrays.fill(array,value);
+    return array;
+  }
+
+  /**
+   * Erzeugt einen mehr-dimensionalen {@link Object}-Array.
+   * @param size Groesse der Array-Dimensionen
+   * @return einen {@code Object[]..[]}
+   */
+  public static Object createArray(int... size) {
+    switch ( size.length ) {
+      case  1: return new Object[size[0]];
+      case  2: return new Object[size[0]][size[1]];
+      case  3: return new Object[size[0]][size[1]][size[2]];
+      case  4: return new Object[size[0]][size[1]][size[2]][size[3]];
+      case  5: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]];
+      case  6: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]];
+      case  7: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]][size[6]];
+      case  8: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]][size[6]][size[7]];
+      case  9: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]][size[6]][size[7]][size[8]];
+      case 10: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]][size[6]][size[7]][size[8]][size[9]];
+      case 11: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]][size[6]][size[7]][size[8]][size[9]][size[10]];
+      case 12: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]][size[6]][size[7]][size[8]][size[9]][size[10]][size[11]];
+      case 13: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]][size[6]][size[7]][size[8]][size[9]][size[10]][size[11]][size[12]];
+      case 14: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]][size[6]][size[7]][size[8]][size[9]][size[10]][size[11]][size[12]][size[13]];
+      case 15: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]][size[6]][size[7]][size[8]][size[9]][size[10]][size[11]][size[12]][size[13]][size[14]];
+      case 16: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]][size[6]][size[7]][size[8]][size[9]][size[10]][size[11]][size[12]][size[13]][size[14]][size[15]];
+      case 17: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]][size[6]][size[7]][size[8]][size[9]][size[10]][size[11]][size[12]][size[13]][size[14]][size[15]][size[16]];
+      case 18: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]][size[6]][size[7]][size[8]][size[9]][size[10]][size[11]][size[12]][size[13]][size[14]][size[15]][size[16]][size[17]];
+      case 19: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]][size[6]][size[7]][size[8]][size[9]][size[10]][size[11]][size[12]][size[13]][size[14]][size[15]][size[16]][size[17]][size[18]];
+      case 20: return new Object[size[0]][size[1]][size[2]][size[3]][size[4]][size[5]][size[6]][size[7]][size[8]][size[9]][size[10]][size[11]][size[12]][size[13]][size[14]][size[15]][size[16]][size[17]][size[18]][size[19]];
+    }
+    throw new IllegalArgumentException("Dimension not supported: "+size.length);
+  }
+
+  /**
+   * Liefert die Dimension eines multi-dimensionalen {@link Object}-Array.<br>
+   * <b>Diese Methode funktioniert nur, wenn das Element 0 in jeder Dimension
+   * belegt ist!</b>
+   * @param array multi-dim. Array (Instanz von {@code Object[]..[]})
+   * @exception ArrayIndexOutOfBoundsException wenn das 0te Element in einer
+   *            Dimension mit {@code null} belegt ist
+   */
+  public static int getArrayDimension(Object array) {
+    int dim = 0;
+    try {
+      for (;; dim++) {
+        array = ((Object[])array)[0];
+      }
+    } catch (ClassCastException err) {
+    }
+    return dim;
+  }
+
+  /**
+   * Liefert die Groessen der einzelnen Dimensionen eines multi-dimensionalen
+   * {@link Object}-Array.<br>
+   * <b>Diese Methode funktioniert nur, wenn das Element 0 in jeder Dimension
+   * belegt ist!</b>
+   * @param array multi-dim. Array (Instanz von {@code Object[]..[]})
+   * @exception ArrayIndexOutOfBoundsException wenn das 0te Element in einer
+   *            Dimension mit {@code null} belegt ist
+   */
+  public static int[] getArrayLength(Object array) {
+    int[] dimSize = new int[ getArrayDimension(array) ];
+    for (int d=0; d<dimSize.length; d++) {
+      dimSize[d] = ((Object[])array).length;
+      array = ( (Object[]) array)[0];
+    }
+    return dimSize;
+  }
+
+  /**
+   * Liefert einen Wert aus einem multi-dimensionalen {@link Object}-Array.
+   * @param array multi-dim. Array (Instanz von {@code Object[]..[]})
+   * @param coord Koordinaten des Arrays
+   * @exception ArrayIndexOutOfBoundsException wenn eine fehlerhafte Koordinate
+   *            angegeben wird
+   */
+  public static Object getArrayValue(Object array, int... coord) {
+    for (int i=0; i<coord.length; i++)
+      array = ((Object[])array)[ coord[i] ];
+    return array;
+  }
+
+  /**
+   * Setzt einen Wert aus einem multi-dimensionalen {@link Object}-Array.
+   * @param array multi-dim. Array (Instanz von {@code Object[]..[]})
+   * @param value zu setzender Wert (Instanz von {@code Object[]..[]})
+   * @param coord Koordinaten des Arrays
+   * @exception ArrayIndexOutOfBoundsException wenn eine fehlerhafte Koordinate
+   *            angegeben wird
+   */
+  public static void setArrayValue(Object array, Object value, int... coord) {
+    for (int i=0; i<coord.length-1; i++)
+      array = ((Object[])array)[ coord[i] ];
+    ((Object[])array)[ coord[coord.length-1] ] = value;
+  }
+
+  /**
+   * Kopiert einen Array (aber nicht dessen Elemente). Darueberhinaus koennen
+   * (einige) Elemente direkt neu belegt werden. Ist das Flag {@code replNull}
+   * auf {@code false} gesetzt, werden {@code null}-Werte in {@code replElem}
+   * ignoriert. So ist es z.B. moeglich, nur das 4. und 5. Element im neuen
+   * Array neu zu belegen und die davor liegenden Elemente unangetastet zu lassen.
+   * @param source   zu kopierender Array
+   * @param replNull Bestimmt, ob {@code null}-Elemente von {@code replElem}
+   *                 im neuen Array gesetzt werden ({@code true}) oder nicht
+   * @param replElem Elemente (beginnend bei Index 0), die nach dem Kopieren
+   *                 im Array neu gesetzt werden
+   * @return Array von der Groesse {@code max(source.length, replElem.length)}
+   */
+  public static <T> T[] cloneArray(T[] source, boolean replNull, T... replElem) {
+    T[] newArray =  java.util.Arrays.copyOf(source, Math.max(source.length, replElem.length));
+    for (int i=0; i<replElem.length; i++)
+      if (replNull || replElem[i] != null)
+        newArray[i] = replElem[i];
+    return newArray;
+  }
+
+  /**
+   * Kopiert einen Array (aber nicht dessen Elemente). Darueberhinaus koennen
+   * (einige) Elemente direkt neu belegt werden.
+   * @param source   zu kopierender Array
+   * @param replElem Elemente (beginnend bei Index 0), die nach dem Kopieren
+   *                 im Array neu gesetzt werden
+   * @return Array von der Groesse {@code max(source.length, replElem.length)}
+   */
+  public static <T> T[] cloneArray(T[] source, T... replElem) {
+    return cloneArray(source,true,replElem);
+  }
+
+  /**
+   * Kopiert einen Array und belegt (einige) Elemente direkt neu.
+   * @param source   zu kopierender Array
+   * @param replElem Elemente (beginnend bei Index 0), die nach dem Kopieren
+   *                 im Array neu gesetzt werden
+   * @return Array von der Groesse {@code max(source.length, replElem.length)}
+   */
+  public static long[] cloneArray(long[] source, long... replElem) {
+    long[] newArray =  java.util.Arrays.copyOf(source, Math.max(source.length, replElem.length));
+    for (int i=0; i<replElem.length; i++)
+      newArray[i] = replElem[i];
+    return newArray;
+  }
+
+  /**
+   * Kopiert einen Array und belegt (einige) Elemente direkt neu.
+   * @param source   zu kopierender Array
+   * @param replElem Elemente (beginnend bei Index 0), die nach dem Kopieren
+   *                 im Array neu gesetzt werden
+   * @return Array von der Groesse {@code max(source.length, replElem.length)}
+   */
+  public static int[] cloneArray(int[] source, int... replElem) {
+    int[] newArray =  java.util.Arrays.copyOf(source, Math.max(source.length, replElem.length));
+    for (int i=0; i<replElem.length; i++)
+      newArray[i] = replElem[i];
+    return newArray;
+  }
+
+  /**
+   * Kopiert einen Array und belegt (einige) Elemente direkt neu.
+   * @param source   zu kopierender Array
+   * @param replElem Elemente (beginnend bei Index 0), die nach dem Kopieren
+   *                 im Array neu gesetzt werden
+   * @return Array von der Groesse {@code max(source.length, replElem.length)}
+   */
+  public static short[] cloneArray(short[] source, short... replElem) {
+    short[] newArray =  java.util.Arrays.copyOf(source, Math.max(source.length, replElem.length));
+    for (int i=0; i<replElem.length; i++)
+      newArray[i] = replElem[i];
+    return newArray;
+  }
+
+  /**
+   * Kopiert einen Array und belegt (einige) Elemente direkt neu.
+   * @param source   zu kopierender Array
+   * @param replElem Elemente (beginnend bei Index 0), die nach dem Kopieren
+   *                 im Array neu gesetzt werden
+   * @return Array von der Groesse {@code max(source.length, replElem.length)}
+   */
+  public static byte[] cloneArray(byte[] source, byte... replElem) {
+    byte[] newArray =  java.util.Arrays.copyOf(source, Math.max(source.length, replElem.length));
+    for (int i=0; i<replElem.length; i++)
+      newArray[i] = replElem[i];
+    return newArray;
+  }
+
+  /**
+   * Kopiert einen Array und belegt (einige) Elemente direkt neu.
+   * @param source   zu kopierender Array
+   * @param replElem Elemente (beginnend bei Index 0), die nach dem Kopieren
+   *                 im Array neu gesetzt werden
+   * @return Array von der Groesse {@code max(source.length, replElem.length)}
+   */
+  public static double[] cloneArray(double[] source, double... replElem) {
+    double[] newArray =  java.util.Arrays.copyOf(source, Math.max(source.length, replElem.length));
+    for (int i=0; i<replElem.length; i++)
+      newArray[i] = replElem[i];
+    return newArray;
+  }
+
+  /**
+   * Kopiert einen Array und belegt (einige) Elemente direkt neu.
+   * @param source   zu kopierender Array
+   * @param replElem Elemente (beginnend bei Index 0), die nach dem Kopieren
+   *                 im Array neu gesetzt werden
+   * @return Array von der Groesse {@code max(source.length, replElem.length)}
+   */
+  public static float[] cloneArray(float[] source, float... replElem) {
+    float[] newArray =  java.util.Arrays.copyOf(source, Math.max(source.length, replElem.length));
+    for (int i=0; i<replElem.length; i++)
+      newArray[i] = replElem[i];
+    return newArray;
+  }
+
+  /**
+   * Kopiert einen Array und belegt (einige) Elemente direkt neu.
+   * @param source   zu kopierender Array
+   * @param replElem Elemente (beginnend bei Index 0), die nach dem Kopieren
+   *                 im Array neu gesetzt werden
+   * @return Array von der Groesse {@code max(source.length, replElem.length)}
+   */
+  public static boolean[] cloneArray(boolean[] source, boolean... replElem) {
+    boolean[] newArray =  java.util.Arrays.copyOf(source, Math.max(source.length, replElem.length));
+    for (int i=0; i<replElem.length; i++)
+      newArray[i] = replElem[i];
+    return newArray;
+  }
+
+  /**
+   * Kopiert einen Array und belegt (einige) Elemente direkt neu.
+   * @param source   zu kopierender Array
+   * @param replElem Elemente (beginnend bei Index 0), die nach dem Kopieren
+   *                 im Array neu gesetzt werden
+   * @return Array von der Groesse {@code max(source.length, replElem.length)}
+   */
+  public static char[] cloneArray(char[] source, char... replElem) {
+    char[] newArray =  java.util.Arrays.copyOf(source, Math.max(source.length, replElem.length));
+    for (int i=0; i<replElem.length; i++)
+      newArray[i] = replElem[i];
+    return newArray;
+  }
+
+  /**
+   * Erweitert einen Array.
+   * @param source   zu kopierender Array
+   * @param newElem  Elemente, die an das Ende des Arrays angehaengt werden
+   * @return Array von der Groesse {@code source.length + newElem.length}
+   */
+  public static <T> T[] extendArray(T[] source, T... newElem) {
+    T[] newArray =  java.util.Arrays.copyOf(source, source.length+newElem.length);
+    for (int i=0; i<newElem.length; i++)
+      newArray[source.length+i] = newElem[i];
+    return newArray;
+  }
+
+  /**
+   * Erweitert einen Array.
+   * @param source   zu kopierender Array
+   * @param newElem  Elemente, die an das Ende des Arrays angehaengt werden
+   * @return Array von der Groesse {@code source.length + newElem.length}
+   */
+  public static long[] extendArray(long[] source, long... newElem) {
+    long[] newArray =  java.util.Arrays.copyOf(source, source.length+newElem.length);
+    for (int i=0; i<newElem.length; i++)
+      newArray[source.length+i] = newElem[i];
+    return newArray;
+  }
+
+  /**
+   * Erweitert einen Array.
+   * @param source   zu kopierender Array
+   * @param newElem  Elemente, die an das Ende des Arrays angehaengt werden
+   * @return Array von der Groesse {@code source.length + newElem.length}
+   */
+  public static int[] extendArray(int[] source, int... newElem) {
+    int[] newArray = java.util.Arrays.copyOf(source, source.length+newElem.length);
+    for (int i=0; i<newElem.length; i++)
+      newArray[source.length+i] = newElem[i];
+    return newArray;
+  }
+
+  /**
+   * Erweitert einen Array.
+   * @param source   zu kopierender Array
+   * @param newElem  Elemente, die an das Ende des Arrays angehaengt werden
+   * @return Array von der Groesse {@code source.length + newElem.length}
+   */
+  public static short[] extendArray(short[] source, short... newElem) {
+    short[] newArray =  java.util.Arrays.copyOf(source, source.length+newElem.length);
+    for (int i=0; i<newElem.length; i++)
+      newArray[source.length+i] = newElem[i];
+    return newArray;
+  }
+
+  /**
+   * Erweitert einen Array.
+   * @param source   zu kopierender Array
+   * @param newElem  Elemente, die an das Ende des Arrays angehaengt werden
+   * @return Array von der Groesse {@code source.length + newElem.length}
+   */
+  public static byte[] extendArray(byte[] source, byte... newElem) {
+    byte[] newArray =  java.util.Arrays.copyOf(source, source.length+newElem.length);
+    for (int i=0; i<newElem.length; i++)
+      newArray[source.length+i] = newElem[i];
+    return newArray;
+  }
+
+  /**
+   * Erweitert einen Array.
+   * @param source   zu kopierender Array
+   * @param newElem  Elemente, die an das Ende des Arrays angehaengt werden
+   * @return Array von der Groesse {@code source.length + newElem.length}
+   */
+  public static double[] extendArray(double[] source, double... newElem) {
+    double[] newArray =  java.util.Arrays.copyOf(source, source.length+newElem.length);
+    for (int i=0; i<newElem.length; i++)
+      newArray[source.length+i] = newElem[i];
+    return newArray;
+  }
+
+  /**
+   * Erweitert einen Array.
+   * @param source   zu kopierender Array
+   * @param newElem  Elemente, die an das Ende des Arrays angehaengt werden
+   * @return Array von der Groesse {@code source.length + newElem.length}
+   */
+  public static float[] extendArray(float[] source, float... newElem) {
+    float[] newArray =  java.util.Arrays.copyOf(source, source.length+newElem.length);
+    for (int i=0; i<newElem.length; i++)
+      newArray[source.length+i] = newElem[i];
+    return newArray;
+  }
+
+  /**
+   * Erweitert einen Array.
+   * @param source   zu kopierender Array
+   * @param newElem  Elemente, die an das Ende des Arrays angehaengt werden
+   * @return Array von der Groesse {@code source.length + newElem.length}
+   */
+  public static boolean[] extendArray(boolean[] source, boolean... newElem) {
+    boolean[] newArray =  java.util.Arrays.copyOf(source, source.length+newElem.length);
+    for (int i=0; i<newElem.length; i++)
+      newArray[source.length+i] = newElem[i];
+    return newArray;
+  }
+
+  /**
+   * Erweitert einen Array.
+   * @param source   zu kopierender Array
+   * @param newElem  Elemente, die an das Ende des Arrays angehaengt werden
+   * @return Array von der Groesse {@code source.length + newElem.length}
+   */
+  public static char[] extendArray(char[] source, char... newElem) {
+    char[] newArray =  java.util.Arrays.copyOf(source, source.length+newElem.length);
+    for (int i=0; i<newElem.length; i++)
+      newArray[source.length+i] = newElem[i];
+    return newArray;
+  }
+
+  /**
+   * Liefert die Klassen-Namen zu einem Array von Klassen.
+   * @param clazz  Klassen
+   * @param simple gibt an, ob der einfache Klassenname ({@code true}) oder der
+   *               komplette Klassenname inkl. Paketname ({@code false})
+   *               zurueckgegeben wird.
+   */
+  public static String[] getClassNames(Class[] clazz, boolean simple) {
+    String[] className = new String[clazz.length];
+    for (int i=0; i<className.length; i++)
+      className[i] = simple ? clazz[i].getSimpleName() : clazz[i].getName();
+    return className;
+  }
+
+  /**
+   * Ruft die Java Garbage Collection auf.
+   * @return Anzahl an Bytes, die durch den Aufruf der Garbage Collection
+   *         freigegeben wurden
+   * @see Runtime#gc()
+   * @see Runtime#freeMemory()
+   */
+  public static long gc() {
+    Runtime runtime = Runtime.getRuntime();
+    long prevFreeMem = runtime.freeMemory();
+    runtime.gc();
+    return runtime.freeMemory() - prevFreeMem;
+  }
+
+  /**
+   * Ruft die Java Garbage Collection solange auf, bis kein Speicher mehr
+   * freigegeben werden kann.
+   * @return Gesamt-Anzahl an Bytes, die durch die Aufrufe der Garbage Collection
+   *         freigegeben wurden
+   * @see #gc()
+   */
+  public static long gcTotal() {
+    long totalFreedMem = 0;
+    for ( long freedMem=0; (freedMem = gc()) > 0; )
+     totalFreedMem += freedMem;
+    return totalFreedMem;
+  }
+
+  /**
+   * Erzeugt einen neuen {@link URLClassLoader}, der vom
+   * {@linkplain ClassLoader#getSystemClassLoader() System-ClassLoaders}
+   * abgeleitet ist.
+   * @param searchPath Pfade, in denen der ClassLoader nach Klassen sucht
+   */
+  public static ClassLoader createClassLoader(URL[] searchPath) {
+    return URLClassLoader.newInstance( searchPath, ClassLoader.getSystemClassLoader() );
+  }
+
+  /**
+   * Erzeugt einen neuen {@link URLClassLoader}, der vom
+   * {@linkplain ClassLoader#getSystemClassLoader() System-ClassLoaders}
+   * abgeleitet ist.
+   * @param searchPath Pfad, in denm der ClassLoader nach Klassen sucht
+   */
+  public static ClassLoader createClassLoader(URL searchPath) {
+    return createClassLoader( new URL[] {searchPath} );
+  }
+
+  /**
+   * Laed eine Klasse. Ggf. wird hierfuer ein neuer {@link ClassLoader}
+   * erzeugt.
+   * @param clazz      Klassenname (inkl. Paket)
+   * @param searchPath Pfade, in denen der ClassLoader nach Klassen sucht
+   *                   (wenn <code>null</code>, wird der
+   *                   {@linkplain ClassLoader#getSystemClassLoader() System-ClassLoader}
+   *                   zum Laden der Klasse verwendet)
+   */
+  public static Class loadClass(String clazz, URL[] searchPath) throws ClassNotFoundException {
+    if ( searchPath == null )
+      return Class.forName(clazz);
+    return createClassLoader(searchPath).loadClass(clazz);
+  }
+
+  /**
+   * Laed eine Klasse. Ggf. wird hierfuer ein neuer {@link ClassLoader}
+   * erzeugt.
+   * @param clazz      Klassenname (inkl. Paket)
+   * @param searchPath Pfad, in dem der ClassLoader nach Klassen sucht
+   *                   (wenn <code>null</code>, wird der
+   *                   {@linkplain ClassLoader#getSystemClassLoader() System-ClassLoader}
+   *                   zum Laden der Klasse verwendet)
+   */
+  public static Class loadClass(String clazz, URL searchPath) throws ClassNotFoundException {
+    if ( searchPath == null )
+      return Class.forName(clazz);
+    return createClassLoader(searchPath).loadClass(clazz);
+  }
+
+  /**
+	 *
+	 * Laed eine Klasse derart das Klassen im Cache ignoriert werden. Dazu ist es erforderlich
+	 * das unter dem Parameter <code>searchPath</code> eine Verzeichnis "META-INF" vorhanden ist.
+	 * Darin muss eine Datei "PREFERRED.LIST" sein. Wie genau diese Datei aufgebaut sein muss, lässt
+	 * sich in der Dokumentation des {@link PreferredClassLoader PreferredClassLoaders} nachlesen.
+	 *
+	 * @param classname  Klassenname (inkl. Paket)
+	 * @param searchPath Pfad, in dem der ClassLoader nach Klassen sucht
+	 *                   (wenn <code>null</code>, wird der System-Klassenpfad
+	 *                   {@linkplain ClassLoader#getSystemResource(String) ClassLoader.getSystemResource("")}
+	 *                   zum Laden der Klasse verwendet)
+	 * @throws ClassNotFoundException
+	 * @see PreferredClassLoader
+	 *
+	 *  @author Dominik Appl
+	 */
+	public static Class loadPreferredClass(String classname, URL searchPath)
+			throws ClassNotFoundException {
+                if ( searchPath == null )
+                  // System-Klassenpfad verwenden
+                  searchPath = ClassLoader.getSystemResource("");
+		PreferredClassLoader classLoader = new PreferredClassLoader(
+				new URL[]{searchPath}, Thread.currentThread()
+						.getContextClassLoader(), null, false);
+		Class loadedClass = classLoader.loadClass(classname);
+		if (loadedClass == null)
+			return Class.forName(classname);
+
+		return loadedClass;
+	}
+
+  /**
+   * Laed eine Klasse neu und erzeugt eine Objekt-Instanz. Als Suchpfad fuer
+   * die Klasse der System-Klassenpfad
+   * {@linkplain ClassLoader#getSystemResource(String) ClassLoader.getSystemResource("")}
+   * verwendet.
+   * @param classname Klassenname (inkl. Paket)
+   * @param param Parameter fuer den Konstruktor-Aufruf
+   * @exception RuntimeException falls irgendein Fehler auftritt
+   */
+  public static Object loadPreferredObject(String classname, Object... param) {
+    return loadPreferredObject(classname,null,param);
+  }
+
+  /**
+   * Laed eine Klasse neu und erzeugt eine Objekt-Instanz.
+   * @param classname Klassenname (inkl. Paket)
+   * @param searchPath Pfad, in dem der ClassLoader nach Klassen sucht
+   *                   (wenn <code>null</code>, wird der System-Klassenpfad
+   *                   {@linkplain ClassLoader#getSystemResource(String) ClassLoader.getSystemResource("")}
+   *                   zum Laden der Klasse verwendet)
+   * @param param Parameter fuer den Konstruktor-Aufruf
+   * @exception RuntimeException falls irgendein Fehler auftritt
+   */
+  public static Object loadPreferredObject(String classname, URL searchPath, Object... param) {
+    try {
+      // Klasse laden
+      Class clazz = loadPreferredClass(classname,searchPath);
+//      // Klassen der Konstruktor-Parameter ermitteln
+//      Class[] paramClass = new Class[ param.length ];
+//      for (int i=0; i<paramClass.length; i++)
+//        paramClass[i] = param[i].getClass();
+//      // Konstruktor fuer Parameter ermitteln (erfordert exakes Matching
+//      // zwischen den Klassen der uebergebenen Parameter und der Klassen
+//      // der Konstruktor-Parameter!)
+//      Constructor constructor = clazz.getConstructor(paramClass);
+      // Konstruktor fuer Parameter ausprobieren
+      for ( Constructor constructor : clazz.getConstructors() )
+        try {
+          return constructor.newInstance(param);
+        } catch (IllegalArgumentException err) {
+        }
+        // kein passender Konstruktor gefunden
+        throw new UnsupportedOperationException("No matching constructor found...");
+    } catch (Exception err) {
+      throw new RuntimeException(err);
+    }
+  }
+
+
+  /**
+   * Liefert das Package einer Klasse erweitert um einen relativen Pfad
+   * in Punkt-Notation.
+   * @param clazz eine Klasse
+   * @param pathExt Erweiterung des Pfads
+   */
+  public static String extendPackagePath(Class clazz, String pathExt) {
+    String packagePath = clazz.getPackage().getName();
+    if ( pathExt != null && !pathExt.trim().equals("") )
+      packagePath += "." + pathExt;
+    return packagePath;
+  }
+
+
+  /**
+   * Prueft einen Identifier auf Korrektheit.
+   * @param identifier Identifier
+   * @exception IllegalArgumentException falls der Identifier nicht-erlaubte
+   *            Zeichen enthaelt
+   * @see Character#isJavaIdentifierStart(char)
+   * @see Character#isJavaIdentifierPart(char)
+   */
+  public static void checkIdentifierAndError(String identifier) {
+    if ( !Character.isJavaIdentifierStart( identifier.charAt(0) ) )
+      throw new IllegalArgumentException("Illegal first character '"+identifier.charAt(0)+"'");
+    for (int i=1; i<identifier.length(); i++) {
+      char c = identifier.charAt(i);
+      if ( !Character.isJavaIdentifierPart(c) )
+        throw new IllegalArgumentException("Illegal inner character '"+c+"'");
+    }
+  }
+
+  /**
+   * Prueft einen Identifier auf Korrektheit.
+   * @param identifier Identifier
+   * @see #checkIdentifierAndError(String)
+   */
+  public static boolean checkIdentifier(String identifier) {
+    try {
+      checkIdentifierAndError(identifier);
+      return true;
+    } catch ( Exception err ) {
+      return false;
+    }
+  }
+
+  /**
+   * Sortiert einen Array aus beliebigen Objekten nach der natuerlichen
+   * Sortierung ihrer {@code toString()}-Werte.
+   * @param objects Objekte
+   */
+  public static void sort(Object[] objects) {
+    Arrays.sort( objects, new Comparator<Object>() {
+      public int compare(Object c1, Object c2) {
+        return c1.toString().compareTo(c2.toString());
+      }
+    });
+  }
+
+  /**
+   * Rundet einen Wert auf Nach- oder Vorkommastellen.
+   * @param value Wert
+   * @param digits Anzahl an Nachkommastellen (negative Werte runden auf
+   *               Vorkommastellen, also 10er-, 100er-, usw. Stelle)
+   * @param mode Modus für das Runden (0 = normal Runden, 1 = Aufrunden, -1 = Abrunden;
+   *             wenn nicht angegeben, wird normal gerundet)
+   */
+  public static double round(double value, int digits, int... mode) {
+    int roundMode = 0; // Default: Normal-Runden
+    if ( mode.length > 0 )
+      roundMode = mode[0];
+
+    // 10er-Potenz fuer Nachkommestellen bilden um vor dem Runden
+    // die Nachkommastellen "vor das Komma" zu schieben
+    double digitsFactor = Math.pow(10, digits);
+    value = value * digitsFactor;
+    // Runden
+    if ( roundMode < 0 )
+      value = Math.floor(value);
+    else if ( roundMode > 0 )
+      value = Math.ceil(value);
+    else
+      value = Math.round(value);
+
+    // Nachkommastellen wieder hinter das Komma schieben
+    return value / digitsFactor;
+  }
+
+  /**
+   * Rundet alle Werte einer {@link Collection} auf Nach- oder Vorkommastellen.<br>
+   * <b>Achtung:</b><br>
+   * Es wird eine neue {@link Collection} des gleichen Typs erzeugt und die
+   * gerundeten Werte darin in der Reihenfolge eingefuegt, wie sie von
+   * {@link Collection#iterator()} geliefert werden! Unter umstaenden kann
+   * die urspruengliche Sortierung verloren gehen! Diese Methode sollte also
+   * im Zweifelsfall nur auf automatisch sortierte {@link Collection Collections}
+   * angewandt werden (z.B. {@link TreeSet}).
+   * @param values Werte
+   * @param digits Anzahl an Nachkommastellen (negative Werte runden auf
+   *               Vorkommastellen, also 10er-, 100er-, usw. Stelle)
+   * @param mode Modus für das Runden (0 = normal Runden, 1 = Aufrunden, -1 = Abrunden;
+   *             wenn nicht angegeben, wird normal gerundet)
+   */
+  public static Collection<Number> round(Collection<Number> values, int digits, int... mode) {
+    try {
+      Collection<Number> newCollection = values.getClass().newInstance();
+      for (Number value : values) {
+        newCollection.add( round(value.doubleValue(),digits,mode) );
+      }
+      return newCollection;
+    } catch (Exception err) {
+      throw new IllegalArgumentException("Can not handle collection: "+getSimpleClassName(values),err);
+    }
+  }
+
+  /**
+   * Erzeugt einen Log4j-Logger fuer ein Objekt. Als Identifier fuer den Logger
+   * wird der Klassenname des Objekts verwendet.
+   * @param object ein Objekt
+   * @return Logger mit dem Namen "NULL", falls das uebergebene Objekt {@code null}
+   *         ist
+   */
+  public static Logger createLogger(Object object) {
+    if ( object == null )
+      return Logger.getLogger("");
+    if ( object instanceof Class )
+      return Logger.getLogger( ((Class)object).getName() );
+    return Logger.getLogger( object.getClass().getName() );
+  }
+
+  /**
+   * Erzeugt einen Error- und einen Debug-Eintrag in einem Logger. Der Error-Eintrag
+   * erhaelt nur die Meldung, der Debug-Eintrag auch die detaillierten Informationen
+   * des Fehlers.
+   * @param logger ein Logger
+   * @param mess   Fehlermeldung (wenn {@code null} wird die Message des Fehlers ausgegeben)
+   * @param err    ein Fehler
+   */
+  public static void logDebugError(Category logger, Object mess, Throwable err) {
+    if ( mess == null )
+      mess = err.getClass().getName()+": "+err.getMessage();
+    logger.error(mess);
+    logger.debug(mess,err);
+  }
+
+  /**
+   * Erzeugt einen Error- und einen Debug-Eintrag in einem Logger. Der Error-Eintrag
+   * erhaelt nur die Meldung, der Debug-Eintrag auch die detaillierten Informationen
+   * des Fehlers.
+   * @param logger ein Logger
+   * @param err    ein Fehler
+   */
+  public static void logDebugError(Category logger, Throwable err) {
+    logDebugError(logger,null,err);
+  }
+
+  /**
+   * Erzeugt einen Warn- und einen Debug-Eintrag in einem Logger. Der Warn-Eintrag
+   * erhaelt nur die Meldung, der Debug-Eintrag auch die detaillierten Informationen
+   * des Fehlers.
+   * @param logger ein Logger
+   * @param mess   Fehlermeldung (wenn {@code null} wird die Message des Fehlers ausgegeben)
+   * @param err    ein Fehler
+   */
+  public static void logDebugWarn(Category logger, Object mess, Throwable err) {
+    if ( mess == null )
+      mess = err.getClass().getName()+": "+err.getMessage();
+    logger.warn(mess);
+    logger.debug(mess,err);
+  }
+
+  /**
+   * Erzeugt einen Warn- und einen Debug-Eintrag in einem Logger. Der Warn-Eintrag
+   * erhaelt nur die Meldung, der Debug-Eintrag auch die detaillierten Informationen
+   * des Fehlers.
+   * @param logger ein Logger
+   * @param err    ein Fehler
+   */
+  public static void logDebugWarn(Category logger, Throwable err) {
+    logDebugWarn(logger,null,err);
+  }
+
+}

Modified: trunk/src/schmitzm/lang/LimitedVector.java
===================================================================
--- trunk/src/schmitzm/lang/LimitedVector.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/lang/LimitedVector.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,16 +1,34 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.lang;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.lang;
-
 import java.util.Collection;
 import java.util.Vector;
 
@@ -21,376 +39,376 @@
 import schmitzm.data.event.ObjectEvent;
 import schmitzm.data.event.ObjectListener;
 import schmitzm.data.event.ObjectTraceable;
-
-/**
- * Diese Klasse stellt einen {@link Vector} dar, der auf eine bestimmte
- * Anzahl an Elementen begrenzt ist. Wird die maximale Anzahl ueberschritten
- * wird automatisch das <b>ERSTE</b> Element der Liste entfernt.<br>
- * Der {@code LimitedVector} eignet sich z.B. gut zum Speichern der letzten
- * 10 geladenen Dateien.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class LimitedVector<E> extends Vector<E> implements ObjectTraceable {
-  /** Speichert die Anzahl der Elemente, die die Liste aufnehmen kann. */
-  protected int maxLoad = 0;
-
-  /** Flag, ob der Vector ein Objekt mehrmals enthalten darf.<br>
-   *  Standard: {@code true} */
-  protected boolean duplAllowed = true;
-
-  // Einfache Implementierung von ObjectTraceable, um die Methoden der
-  // Listener-Verwaltung nicht doppelt implementieren zu muessen
-  private AbstractObjectTraceable objectTraceableProxy = new AbstractObjectTraceable() {
-  };
-
-  /**
-   * Erzeugt eine leere Liste.
-   * @param maxLoad maximale Anzahl an Elementen, die die Liste aufnehmen kann
-   */
-  public LimitedVector(int maxLoad) {
-    super(maxLoad);
-    setMaxLoad(maxLoad);
-  }
-
-  /**
-   * Liefert die maximale Anzahl an Elementen, die die Liste aufnehmen kann.
-   */
-  public int getMaxLoad() {
-    return maxLoad;
-  }
-
-  /**
-   * Setzt die maximale Anzahl an Elementen, die die Liste aufnehmen kann.
-   * Ist der neue Wert kleiner als der alte, so werden alle ueberzaehligen
-   * Elemente sofort entfernt!
-   * @param maxLoad Maximal-Anzahl an Elementen
-   */
-  public void setMaxLoad(int maxLoad) {
-    this.maxLoad = maxLoad;
-    truncate();
-  }
-
-  /**
-   * Loescht solange das letzte Element der Liste, bis die maximale Anzahl
-   * an Elementen erreicht ist.
-   */
-  protected void truncate() {
-    while( size() > maxLoad )
-      removeElementAt( 0 );
-  }
-
-  /**
-   * Prueft, ob die Liste ein Objekt mehrmals enthalten darf.
-   * @see #setDuplicatedAllowed(boolean)
-   */
-  public boolean getDuplicatedAllowed() {
-    return this.duplAllowed;
-  }
-
-  /**
-   * Bestimmt, ob die Liste ein Objekt mehrmals enthalten darf.<br>
-   * Standard: {@code false}<br>
-   * <b>Bemerkung:</b><br>
-   * Die Aenderung dieser Eigenschaft wirkt sich NICHT auf den aktuellen Inhalt
-   * der Liste aus. Bestehende Duplikate in der Liste bleiben erhalten!!
-   * @param duplAllowed bei {@code false} wird vor dem Einfuegen ein etwaiges
-   *                    Duplikat aus der Liste entfernt
-   */
-  public void setDuplicatedAllowed(boolean duplAllowed) {
-    this.duplAllowed = duplAllowed;
-  }
-
-  ///////////////////////////////////////////////////////////////////
-  /////////////////   Ueberschreiben von Vector   ///////////////////
-  ///////////////////////////////////////////////////////////////////
-  /**
-   * Fuegt ein Element in die Liste ein. Danach werden alle ueberzaehligen
-   * Element geloescht. Erzeugt ein {@link ObjectChangeEvent} falls sich der
-   * Inhalt des Vectors aendert.<br>
-   * <b>Bemerkung:</b><br>
-   * Diese Methode macht nichts, falls sie bei bereits voll gefuellter Liste
-   * mit Index 0 aufgerufen wird, da in diesem Fall das neue Element sofort
-   * ueberzaehlig ist.<br>
-   * <b>ACHTUNG:</b><br>
-   * Bei automatischer Duplikat-Eleminierung kann diese Methode zu Problemen
-   * fuehren, da ERST die Duplikate geloescht werden und dann die Einfuege-
-   * Operation vorgenommen wird. {@code index} ist dann evt. nicht mehr die
-   * gewuenschte Einfuege-Position!!
-   * @param obj einzufuegendes Objekt
-   * @param index Index an dem das Element eingefuegt wird
-   */
-  public synchronized void insertElementAt(E obj, int index) {
-    if ( size() >= getMaxLoad() && index == 0 )
-      return;
-
-    // etwaige Duplikate entfernen
-    if ( !duplAllowed )
-      while( remove(obj) );
-
-    int oldSize = size(); //
-    super.insertElementAt(obj,index);
-    if ( size() != oldSize ) {
-      truncate();
-      fireEvent( new ObjectChangeEvent(new Invoker(this),null,obj) );
-    }
-  }
-
-  /**
-   * Belegt eine Listenposition neu und erzeugt ein
-   * {@link ObjectChangeEvent}, falls sich der Listen-Inhalt aendert.<br>
-   * <b>ACHTUNG:</b><br>
-   * Bei automatischer Duplikat-Eleminierung kann diese Methode zu Problemen
-   * fuehren, da ERST die Duplikate geloescht werden und dann die Set-
-   * Operation vorgenommen wird. {@code index} ist dann evt. nicht mehr die
-   * gewuenschte Set-Position!!
-   * @param obj neues Listen-Element
-   * @param index Listen-Position
-   */
-  public synchronized void setElementAt(E obj, int index) {
-    // etwaige Duplikate entfernen
-    if ( !duplAllowed )
-      while( remove(obj) );
-
-    E oldObj = this.elementAt(index);
-    super.setElementAt(obj,index);
-    if ( oldObj != obj )
-      fireEvent( new ObjectChangeEvent(new Invoker(this),oldObj,obj) );
-  }
-
-  /**
-   * Belegt eine Listenposition neu und erzeugt ein
-   * {@link ObjectChangeEvent}, falls sich der Listen-Inhalt aendert.<br>
-   * <b>ACHTUNG:</b><br>
-   * Bei automatischer Duplikat-Eleminierung kann diese Methode zu Problemen
-   * fuehren, da ERST die Duplikate geloescht werden und dann die Set-
-   * Operation vorgenommen wird. {@code index} ist dann evt. nicht mehr die
-   * gewuenschte Set-Position!!
-   * @param obj neues Listen-Element
-   * @param index Listen-Position
-   */
-  public synchronized E set(int index, E obj) {
-    // etwaige Duplikate entfernen
-    if ( !duplAllowed )
-      while( remove(obj) );
-
-    E oldObj = super.set(index,obj);
-    if ( oldObj != obj )
-      fireEvent( new ObjectChangeEvent(new Invoker(this),oldObj,obj) );
-    return oldObj;
-  }
-
-  /**
-   * Fuegt ein Element in am Ende der Liste ein. Danach werden alle ueberzaehligen
-   * Element geloescht. Erzeugt ein {@link ObjectChangeEvent} falls
-   * sich der Inhalt des Vectors aendert.
-   * @param obj einzufuegendes Objekt
-   */
-  public synchronized void addElement(E obj) {
-    // etwaige Duplikate entfernen
-    if ( !duplAllowed )
-      while( remove(obj) );
-
-    int oldSize = size();
-    super.addElement(obj);
-    if ( size() != oldSize ) {
-      truncate();
-      fireEvent( new ObjectChangeEvent(new Invoker(this),null,obj) );
-    }
-  }
-
-  /**
-   * Fuegt ein Element am Ende der Liste ein. Danach werden alle ueberzaehligen
-   * Element geloescht. Erzeugt ein {@link ObjectChangeEvent} falls
-   * sich der Inhalt des Vectors aendert.
-   * @param o einzufuegendes Objekt
-   */
-  public synchronized boolean add(E o) {
-    // etwaige Duplikate entfernen
-    if ( !duplAllowed )
-      while( remove(o) );
-
-    boolean changed = super.add(o);
-    if ( changed ) {
-      truncate();
-      fireEvent( new ObjectChangeEvent(new Invoker(this),null,o) );
-    }
-    return changed;
-  }
-
-  /**
-   * Fuegt alle Elemente einer {@link Collection} am Ende der Liste ein.
-   * Danach werden alle ueberzaehligen Element geloescht.  Erzeugt ein
-   * {@link GeneralObjectChangeEvent} falls sich der Inhalt des Vectors aendert.
-   * @param c einzufuegende Objekte
-   */
-  public synchronized boolean addAll(Collection<? extends E> c) {
-    // etwaige Duplikate entfernen
-    if ( !duplAllowed )
-      while( removeAll(c) );
-
-    boolean changed = super.addAll(c);
-    if ( changed ) {
-      truncate();
-      fireEvent( new GeneralObjectChangeEvent(this) );
-    }
-    return changed;
-  }
-
-  /**
-   * Fuegt alle Elemente einer {@link Collection} in die Liste ein.
-   * Danach werden alle ueberzaehligen Element geloescht. Erzeugt ein
-   * {@link GeneralObjectChangeEvent} falls sich der Inhalt des Vectors aendert.<br>
-   * <b>Bemerkung:</b><br>
-   * Diese Methode macht nichts, falls sie bei bereits voll gefuellter Liste
-   * mit Index 0 aufgerufen wird, da in diesem Fall die neuen Elemente auch
-   * die ueberzaehligen sind.
-   * @param index Listen-Position ab der die Elemente eingefuegt werden
-   * @param c einzufuegende Objekte
-   */
-  public synchronized boolean addAll(int index, Collection<? extends E> c) {
-    // etwaiges Duplikat entfernen
-    if ( !duplAllowed )
-      while( removeAll(c) );
-
-    if ( size() >= getMaxLoad() && index == 0 )
-      return false;
-
-    boolean changed = super.addAll(index,c);
-    if ( changed ) {
-      truncate();
-      fireEvent( new GeneralObjectChangeEvent(this) );
-    }
-    return changed;
-  }
-
-  /**
-   * Verhaelt sich wie {@link Vector#trimToSize()} und erzeugt ein
-   * {@link GeneralObjectChangeEvent}.
-   */
-  public synchronized void trimToSize() {
-    super.trimToSize();
-    fireEvent( new GeneralObjectChangeEvent(this) );
-  }
-
-  /**
-   * Verhaelt sich wie {@link Vector#setSize(int)} und erzeugt ein
-   * {@link GeneralObjectChangeEvent}.
-   */
-  public synchronized void setSize(int newSize) {
-    super.setSize(newSize);
-    fireEvent( new GeneralObjectChangeEvent(this) );
-  }
-
-  /**
-   * Verhaelt sich wie {@link Vector#removeElementAt(int)} und erzeugt ein
-   * {@link ObjectChangeEvent}, falls sich der Listen-Inhalt aendert.
-   */
-  public synchronized void removeElementAt(int index) {
-    E oldObj = this.elementAt(index);
-    super.removeElementAt(index);
-    fireEvent( new ObjectChangeEvent(new Invoker(this),oldObj,null) );
-  }
-
-  /**
-   * Verhaelt sich wie {@link Vector#removeAllElements()} und erzeugt ein
-   * {@link GeneralObjectChangeEvent}, falls sich der Listen-Inhalt aendert.
-   */
-  public synchronized void removeAllElements() {
-    if ( size() == 0 )
-      return;
-    super.removeAllElements();
-    fireEvent( new GeneralObjectChangeEvent(this) );
-  }
-
-  /**
-   * Verhaelt sich wie {@link Vector#remove(int)} und erzeugt ein
-   * {@link ObjectChangeEvent}, falls sich der Listen-Inhalt aendert.
-   */
-  public synchronized E remove(int index) {
-    E oldObj = super.remove(index);
-    fireEvent( new ObjectChangeEvent(new Invoker(this),oldObj,null) );
-    return oldObj;
-  }
-
-  /**
-   * Verhaelt sich wie {@link Vector#removeAll(Collection)} und erzeugt ein
-   * {@link GeneralObjectChangeEvent}, falls sich der Listen-Inhalt aendert.
-   */
-  public synchronized boolean removeAll(Collection<?> c) {
-    boolean changed =  super.removeAll(c);
-    if ( changed )
-      fireEvent(new GeneralObjectChangeEvent(this));
-    return changed;
-  }
-
-  /**
-   * Verhaelt sich wie {@link Vector#retainAll(Collection)} und erzeugt ein
-   * {@link GeneralObjectChangeEvent}, falls sich der Listen-Inhalt aendert.
-   */
-  public synchronized boolean retainAll(Collection<?> c)  {
-    boolean changed =  super.retainAll(c);
-    if ( changed )
-      fireEvent(new GeneralObjectChangeEvent(this));
-    return changed;
-  }
-
-  /**
-   * Verhaelt sich wie {@link Vector#removeRange(int,int)} und erzeugt ein
-   * {@link GeneralObjectChangeEvent}, falls sich der Listen-Inhalt aendert.
-   */
-  protected synchronized void removeRange(int fromIndex, int toIndex) {
-    int oldSize = size();
-    super.removeRange(fromIndex,toIndex);
-    if ( size() != oldSize )
-      fireEvent(new GeneralObjectChangeEvent(this));
-  }
-
-  ///////////////////////////////////////////////////////////////////
-  ////////////   Implementierung von ObjectTraceable   //////////////
-  ///////////////////////////////////////////////////////////////////
-  /**
-   * Fuegt dem Objekt einen Listener hinzu, der bei Aenderungen informiert wird.
-   */
-  public void addObjectListener(ObjectListener listener) {
-    this.objectTraceableProxy.addObjectListener(listener);
-  }
-
-  /**
-   * Entfernt einen Listener von dem Objekt.
-   */
-  public void removeObjectListener(ObjectListener listener) {
-    this.objectTraceableProxy.removeObjectListener(listener);
-  }
-
-  /**
-   * Checkt, ob der angegebene Listener dem Objekt zugeordnet ist.
-   */
-  public boolean containsObjectListener(ObjectListener l) {
-    return this.objectTraceableProxy.containsObjectListener(l);
-  }
-
-  /**
-   * Liefert alle Listener eines bestimmten Typs.
-   * @param type Art des Listeners (Filter)
-   */
-  public ObjectListener[] getObjectListener(Class type) {
-    return this.objectTraceableProxy.getObjectListener(type);
-  }
-
-  /**
-   * Informiert alle Listener, dass sich das Objekt (this) geaendert hat.
-   */
-  public void fireEvent(ObjectEvent e) {
-    this.objectTraceableProxy.fireEvent(e);
-  }
-
-  /**
-   * Informiert alle Listener eine bestimmten Klasse, dass sich das Objekt
-   * (this) geaendert hat.
-   */
-  public void fireEvent(ObjectEvent e, Class c) {
-    this.objectTraceableProxy.fireEvent(e, c);
-  }
-
-}
+
+/**
+ * Diese Klasse stellt einen {@link Vector} dar, der auf eine bestimmte
+ * Anzahl an Elementen begrenzt ist. Wird die maximale Anzahl ueberschritten
+ * wird automatisch das <b>ERSTE</b> Element der Liste entfernt.<br>
+ * Der {@code LimitedVector} eignet sich z.B. gut zum Speichern der letzten
+ * 10 geladenen Dateien.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class LimitedVector<E> extends Vector<E> implements ObjectTraceable {
+  /** Speichert die Anzahl der Elemente, die die Liste aufnehmen kann. */
+  protected int maxLoad = 0;
+
+  /** Flag, ob der Vector ein Objekt mehrmals enthalten darf.<br>
+   *  Standard: {@code true} */
+  protected boolean duplAllowed = true;
+
+  // Einfache Implementierung von ObjectTraceable, um die Methoden der
+  // Listener-Verwaltung nicht doppelt implementieren zu muessen
+  private AbstractObjectTraceable objectTraceableProxy = new AbstractObjectTraceable() {
+  };
+
+  /**
+   * Erzeugt eine leere Liste.
+   * @param maxLoad maximale Anzahl an Elementen, die die Liste aufnehmen kann
+   */
+  public LimitedVector(int maxLoad) {
+    super(maxLoad);
+    setMaxLoad(maxLoad);
+  }
+
+  /**
+   * Liefert die maximale Anzahl an Elementen, die die Liste aufnehmen kann.
+   */
+  public int getMaxLoad() {
+    return maxLoad;
+  }
+
+  /**
+   * Setzt die maximale Anzahl an Elementen, die die Liste aufnehmen kann.
+   * Ist der neue Wert kleiner als der alte, so werden alle ueberzaehligen
+   * Elemente sofort entfernt!
+   * @param maxLoad Maximal-Anzahl an Elementen
+   */
+  public void setMaxLoad(int maxLoad) {
+    this.maxLoad = maxLoad;
+    truncate();
+  }
+
+  /**
+   * Loescht solange das letzte Element der Liste, bis die maximale Anzahl
+   * an Elementen erreicht ist.
+   */
+  protected void truncate() {
+    while( size() > maxLoad )
+      removeElementAt( 0 );
+  }
+
+  /**
+   * Prueft, ob die Liste ein Objekt mehrmals enthalten darf.
+   * @see #setDuplicatedAllowed(boolean)
+   */
+  public boolean getDuplicatedAllowed() {
+    return this.duplAllowed;
+  }
+
+  /**
+   * Bestimmt, ob die Liste ein Objekt mehrmals enthalten darf.<br>
+   * Standard: {@code false}<br>
+   * <b>Bemerkung:</b><br>
+   * Die Aenderung dieser Eigenschaft wirkt sich NICHT auf den aktuellen Inhalt
+   * der Liste aus. Bestehende Duplikate in der Liste bleiben erhalten!!
+   * @param duplAllowed bei {@code false} wird vor dem Einfuegen ein etwaiges
+   *                    Duplikat aus der Liste entfernt
+   */
+  public void setDuplicatedAllowed(boolean duplAllowed) {
+    this.duplAllowed = duplAllowed;
+  }
+
+  ///////////////////////////////////////////////////////////////////
+  /////////////////   Ueberschreiben von Vector   ///////////////////
+  ///////////////////////////////////////////////////////////////////
+  /**
+   * Fuegt ein Element in die Liste ein. Danach werden alle ueberzaehligen
+   * Element geloescht. Erzeugt ein {@link ObjectChangeEvent} falls sich der
+   * Inhalt des Vectors aendert.<br>
+   * <b>Bemerkung:</b><br>
+   * Diese Methode macht nichts, falls sie bei bereits voll gefuellter Liste
+   * mit Index 0 aufgerufen wird, da in diesem Fall das neue Element sofort
+   * ueberzaehlig ist.<br>
+   * <b>ACHTUNG:</b><br>
+   * Bei automatischer Duplikat-Eleminierung kann diese Methode zu Problemen
+   * fuehren, da ERST die Duplikate geloescht werden und dann die Einfuege-
+   * Operation vorgenommen wird. {@code index} ist dann evt. nicht mehr die
+   * gewuenschte Einfuege-Position!!
+   * @param obj einzufuegendes Objekt
+   * @param index Index an dem das Element eingefuegt wird
+   */
+  public synchronized void insertElementAt(E obj, int index) {
+    if ( size() >= getMaxLoad() && index == 0 )
+      return;
+
+    // etwaige Duplikate entfernen
+    if ( !duplAllowed )
+      while( remove(obj) );
+
+    int oldSize = size(); //
+    super.insertElementAt(obj,index);
+    if ( size() != oldSize ) {
+      truncate();
+      fireEvent( new ObjectChangeEvent(new Invoker(this),null,obj) );
+    }
+  }
+
+  /**
+   * Belegt eine Listenposition neu und erzeugt ein
+   * {@link ObjectChangeEvent}, falls sich der Listen-Inhalt aendert.<br>
+   * <b>ACHTUNG:</b><br>
+   * Bei automatischer Duplikat-Eleminierung kann diese Methode zu Problemen
+   * fuehren, da ERST die Duplikate geloescht werden und dann die Set-
+   * Operation vorgenommen wird. {@code index} ist dann evt. nicht mehr die
+   * gewuenschte Set-Position!!
+   * @param obj neues Listen-Element
+   * @param index Listen-Position
+   */
+  public synchronized void setElementAt(E obj, int index) {
+    // etwaige Duplikate entfernen
+    if ( !duplAllowed )
+      while( remove(obj) );
+
+    E oldObj = this.elementAt(index);
+    super.setElementAt(obj,index);
+    if ( oldObj != obj )
+      fireEvent( new ObjectChangeEvent(new Invoker(this),oldObj,obj) );
+  }
+
+  /**
+   * Belegt eine Listenposition neu und erzeugt ein
+   * {@link ObjectChangeEvent}, falls sich der Listen-Inhalt aendert.<br>
+   * <b>ACHTUNG:</b><br>
+   * Bei automatischer Duplikat-Eleminierung kann diese Methode zu Problemen
+   * fuehren, da ERST die Duplikate geloescht werden und dann die Set-
+   * Operation vorgenommen wird. {@code index} ist dann evt. nicht mehr die
+   * gewuenschte Set-Position!!
+   * @param obj neues Listen-Element
+   * @param index Listen-Position
+   */
+  public synchronized E set(int index, E obj) {
+    // etwaige Duplikate entfernen
+    if ( !duplAllowed )
+      while( remove(obj) );
+
+    E oldObj = super.set(index,obj);
+    if ( oldObj != obj )
+      fireEvent( new ObjectChangeEvent(new Invoker(this),oldObj,obj) );
+    return oldObj;
+  }
+
+  /**
+   * Fuegt ein Element in am Ende der Liste ein. Danach werden alle ueberzaehligen
+   * Element geloescht. Erzeugt ein {@link ObjectChangeEvent} falls
+   * sich der Inhalt des Vectors aendert.
+   * @param obj einzufuegendes Objekt
+   */
+  public synchronized void addElement(E obj) {
+    // etwaige Duplikate entfernen
+    if ( !duplAllowed )
+      while( remove(obj) );
+
+    int oldSize = size();
+    super.addElement(obj);
+    if ( size() != oldSize ) {
+      truncate();
+      fireEvent( new ObjectChangeEvent(new Invoker(this),null,obj) );
+    }
+  }
+
+  /**
+   * Fuegt ein Element am Ende der Liste ein. Danach werden alle ueberzaehligen
+   * Element geloescht. Erzeugt ein {@link ObjectChangeEvent} falls
+   * sich der Inhalt des Vectors aendert.
+   * @param o einzufuegendes Objekt
+   */
+  public synchronized boolean add(E o) {
+    // etwaige Duplikate entfernen
+    if ( !duplAllowed )
+      while( remove(o) );
+
+    boolean changed = super.add(o);
+    if ( changed ) {
+      truncate();
+      fireEvent( new ObjectChangeEvent(new Invoker(this),null,o) );
+    }
+    return changed;
+  }
+
+  /**
+   * Fuegt alle Elemente einer {@link Collection} am Ende der Liste ein.
+   * Danach werden alle ueberzaehligen Element geloescht.  Erzeugt ein
+   * {@link GeneralObjectChangeEvent} falls sich der Inhalt des Vectors aendert.
+   * @param c einzufuegende Objekte
+   */
+  public synchronized boolean addAll(Collection<? extends E> c) {
+    // etwaige Duplikate entfernen
+    if ( !duplAllowed )
+      while( removeAll(c) );
+
+    boolean changed = super.addAll(c);
+    if ( changed ) {
+      truncate();
+      fireEvent( new GeneralObjectChangeEvent(this) );
+    }
+    return changed;
+  }
+
+  /**
+   * Fuegt alle Elemente einer {@link Collection} in die Liste ein.
+   * Danach werden alle ueberzaehligen Element geloescht. Erzeugt ein
+   * {@link GeneralObjectChangeEvent} falls sich der Inhalt des Vectors aendert.<br>
+   * <b>Bemerkung:</b><br>
+   * Diese Methode macht nichts, falls sie bei bereits voll gefuellter Liste
+   * mit Index 0 aufgerufen wird, da in diesem Fall die neuen Elemente auch
+   * die ueberzaehligen sind.
+   * @param index Listen-Position ab der die Elemente eingefuegt werden
+   * @param c einzufuegende Objekte
+   */
+  public synchronized boolean addAll(int index, Collection<? extends E> c) {
+    // etwaiges Duplikat entfernen
+    if ( !duplAllowed )
+      while( removeAll(c) );
+
+    if ( size() >= getMaxLoad() && index == 0 )
+      return false;
+
+    boolean changed = super.addAll(index,c);
+    if ( changed ) {
+      truncate();
+      fireEvent( new GeneralObjectChangeEvent(this) );
+    }
+    return changed;
+  }
+
+  /**
+   * Verhaelt sich wie {@link Vector#trimToSize()} und erzeugt ein
+   * {@link GeneralObjectChangeEvent}.
+   */
+  public synchronized void trimToSize() {
+    super.trimToSize();
+    fireEvent( new GeneralObjectChangeEvent(this) );
+  }
+
+  /**
+   * Verhaelt sich wie {@link Vector#setSize(int)} und erzeugt ein
+   * {@link GeneralObjectChangeEvent}.
+   */
+  public synchronized void setSize(int newSize) {
+    super.setSize(newSize);
+    fireEvent( new GeneralObjectChangeEvent(this) );
+  }
+
+  /**
+   * Verhaelt sich wie {@link Vector#removeElementAt(int)} und erzeugt ein
+   * {@link ObjectChangeEvent}, falls sich der Listen-Inhalt aendert.
+   */
+  public synchronized void removeElementAt(int index) {
+    E oldObj = this.elementAt(index);
+    super.removeElementAt(index);
+    fireEvent( new ObjectChangeEvent(new Invoker(this),oldObj,null) );
+  }
+
+  /**
+   * Verhaelt sich wie {@link Vector#removeAllElements()} und erzeugt ein
+   * {@link GeneralObjectChangeEvent}, falls sich der Listen-Inhalt aendert.
+   */
+  public synchronized void removeAllElements() {
+    if ( size() == 0 )
+      return;
+    super.removeAllElements();
+    fireEvent( new GeneralObjectChangeEvent(this) );
+  }
+
+  /**
+   * Verhaelt sich wie {@link Vector#remove(int)} und erzeugt ein
+   * {@link ObjectChangeEvent}, falls sich der Listen-Inhalt aendert.
+   */
+  public synchronized E remove(int index) {
+    E oldObj = super.remove(index);
+    fireEvent( new ObjectChangeEvent(new Invoker(this),oldObj,null) );
+    return oldObj;
+  }
+
+  /**
+   * Verhaelt sich wie {@link Vector#removeAll(Collection)} und erzeugt ein
+   * {@link GeneralObjectChangeEvent}, falls sich der Listen-Inhalt aendert.
+   */
+  public synchronized boolean removeAll(Collection<?> c) {
+    boolean changed =  super.removeAll(c);
+    if ( changed )
+      fireEvent(new GeneralObjectChangeEvent(this));
+    return changed;
+  }
+
+  /**
+   * Verhaelt sich wie {@link Vector#retainAll(Collection)} und erzeugt ein
+   * {@link GeneralObjectChangeEvent}, falls sich der Listen-Inhalt aendert.
+   */
+  public synchronized boolean retainAll(Collection<?> c)  {
+    boolean changed =  super.retainAll(c);
+    if ( changed )
+      fireEvent(new GeneralObjectChangeEvent(this));
+    return changed;
+  }
+
+  /**
+   * Verhaelt sich wie {@link Vector#removeRange(int,int)} und erzeugt ein
+   * {@link GeneralObjectChangeEvent}, falls sich der Listen-Inhalt aendert.
+   */
+  protected synchronized void removeRange(int fromIndex, int toIndex) {
+    int oldSize = size();
+    super.removeRange(fromIndex,toIndex);
+    if ( size() != oldSize )
+      fireEvent(new GeneralObjectChangeEvent(this));
+  }
+
+  ///////////////////////////////////////////////////////////////////
+  ////////////   Implementierung von ObjectTraceable   //////////////
+  ///////////////////////////////////////////////////////////////////
+  /**
+   * Fuegt dem Objekt einen Listener hinzu, der bei Aenderungen informiert wird.
+   */
+  public void addObjectListener(ObjectListener listener) {
+    this.objectTraceableProxy.addObjectListener(listener);
+  }
+
+  /**
+   * Entfernt einen Listener von dem Objekt.
+   */
+  public void removeObjectListener(ObjectListener listener) {
+    this.objectTraceableProxy.removeObjectListener(listener);
+  }
+
+  /**
+   * Checkt, ob der angegebene Listener dem Objekt zugeordnet ist.
+   */
+  public boolean containsObjectListener(ObjectListener l) {
+    return this.objectTraceableProxy.containsObjectListener(l);
+  }
+
+  /**
+   * Liefert alle Listener eines bestimmten Typs.
+   * @param type Art des Listeners (Filter)
+   */
+  public ObjectListener[] getObjectListener(Class type) {
+    return this.objectTraceableProxy.getObjectListener(type);
+  }
+
+  /**
+   * Informiert alle Listener, dass sich das Objekt (this) geaendert hat.
+   */
+  public void fireEvent(ObjectEvent e) {
+    this.objectTraceableProxy.fireEvent(e);
+  }
+
+  /**
+   * Informiert alle Listener eine bestimmten Klasse, dass sich das Objekt
+   * (this) geaendert hat.
+   */
+  public void fireEvent(ObjectEvent e, Class c) {
+    this.objectTraceableProxy.fireEvent(e, c);
+  }
+
+}

Modified: trunk/src/schmitzm/lang/LocaleComparator.java
===================================================================
--- trunk/src/schmitzm/lang/LocaleComparator.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/lang/LocaleComparator.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,51 +1,70 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.lang;
-
-import java.util.Comparator;
-import java.util.Locale;
-
-/**
- * {@code Comparator} um {@link Locale Locales} zu vergleichen. Es kann nach
- * der Beschreibung (in der aktuellen Default-Locale) verglichen werden oder
- * nach dem Sprach-Code.
- * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class LocaleComparator implements Comparator<Locale> {
-  /** Flag, ob nach der {@linkplain Locale#getDisplayName() Beschreibung}
-   *  verglichen wird ({@code true}) oder nach dem
-   *  {@linkplain Locale#toString() Sprach-Code}. */
-  protected boolean compareDesc = false;
-
-  /**
-   * Erzeugt einen neuen {@code Comparator}.
-   * @param compareDesc Flag, ob nach der {@linkplain Locale#getDisplayName() Beschreibung}
-   *                    verglichen wird ({@code true}) oder nach dem
-   *                    {@linkplain Locale#toString() Sprach-Code}.
-   */
-  public LocaleComparator(boolean compareDesc) {
-    this.compareDesc = compareDesc;
-  }
-
-  /**
-   * Fuehrt den Vergleich aus.
-   * @param loc1 eine Locale
-   * @param loc2 eine andere Locale
-   * @return ein negativer Wert fuer {@code loc1 < loc2}, 0 für {@code loc1 = loc2}
-   *         oder ein positiver Wert fuer {@code loc1 > loc2}
-   */
-  public int compare(Locale loc1, Locale loc2) {
-    if ( compareDesc )
-      return loc1.getDisplayName().compareTo(loc2.getDisplayName());
-    return loc1.toString().compareTo(loc2.toString());
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.lang;
+
+import java.util.Comparator;
+import java.util.Locale;
+
+/**
+ * {@code Comparator} um {@link Locale Locales} zu vergleichen. Es kann nach
+ * der Beschreibung (in der aktuellen Default-Locale) verglichen werden oder
+ * nach dem Sprach-Code.
+ * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class LocaleComparator implements Comparator<Locale> {
+  /** Flag, ob nach der {@linkplain Locale#getDisplayName() Beschreibung}
+   *  verglichen wird ({@code true}) oder nach dem
+   *  {@linkplain Locale#toString() Sprach-Code}. */
+  protected boolean compareDesc = false;
+
+  /**
+   * Erzeugt einen neuen {@code Comparator}.
+   * @param compareDesc Flag, ob nach der {@linkplain Locale#getDisplayName() Beschreibung}
+   *                    verglichen wird ({@code true}) oder nach dem
+   *                    {@linkplain Locale#toString() Sprach-Code}.
+   */
+  public LocaleComparator(boolean compareDesc) {
+    this.compareDesc = compareDesc;
+  }
+
+  /**
+   * Fuehrt den Vergleich aus.
+   * @param loc1 eine Locale
+   * @param loc2 eine andere Locale
+   * @return ein negativer Wert fuer {@code loc1 < loc2}, 0 für {@code loc1 = loc2}
+   *         oder ein positiver Wert fuer {@code loc1 > loc2}
+   */
+  public int compare(Locale loc1, Locale loc2) {
+    if ( compareDesc )
+      return loc1.getDisplayName().compareTo(loc2.getDisplayName());
+    return loc1.toString().compareTo(loc2.toString());
+  }
+}

Modified: trunk/src/schmitzm/lang/MultiDimArray.java
===================================================================
--- trunk/src/schmitzm/lang/MultiDimArray.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/lang/MultiDimArray.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,14 +1,32 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package schmitzm.lang;
 
 import java.lang.reflect.Array;

Modified: trunk/src/schmitzm/lang/NamedObject.java
===================================================================
--- trunk/src/schmitzm/lang/NamedObject.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/lang/NamedObject.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,31 +1,49 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.lang;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+/**
+ * Dieses Interface implementieren alle Objekte, die "in irgendeiner Form"
+ * eine Beschreibung (oder einen Namen) besitzen.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public interface NamedObject {
+  /**
+   * Liefert den Namen des Objekts.
+   */
+  public String getName();
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.lang;
-
-/**
- * Dieses Interface implementieren alle Objekte, die "in irgendeiner Form"
- * eine Beschreibung (oder einen Namen) besitzen.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public interface NamedObject {
-  /**
-   * Liefert den Namen des Objekts.
-   */
-  public String getName();
-
-  /**
-   * Setzt den Namen des Objekts.
-   * @param name neuer Name
-   */
-  public void setName(String name);
-}
+  /**
+   * Setzt den Namen des Objekts.
+   * @param name neuer Name
+   */
+  public void setName(String name);
+}

Modified: trunk/src/schmitzm/lang/OperationCanceledException.java
===================================================================
--- trunk/src/schmitzm/lang/OperationCanceledException.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/lang/OperationCanceledException.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,36 +1,54 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.lang;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+/**
+ * Diese Exception stellt keinen wirklichen Fehler dar, sondern lediglich
+ * eine Information, dass die aktuelle Operation abgebrochen wurde und
+ * eine etwaige Operationen-Folge beendet werden sollte.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class OperationCanceledException extends RuntimeException {
+  /**
+   * Erzeugt eine neue <code>OperationCanceledException</code>.
+   */
+  public OperationCanceledException() {
+    this(null);
+  }
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.lang;
-
-/**
- * Diese Exception stellt keinen wirklichen Fehler dar, sondern lediglich
- * eine Information, dass die aktuelle Operation abgebrochen wurde und
- * eine etwaige Operationen-Folge beendet werden sollte.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class OperationCanceledException extends RuntimeException {
-  /**
-   * Erzeugt eine neue <code>OperationCanceledException</code>.
-   */
-  public OperationCanceledException() {
-    this(null);
-  }
-
-  /**
-   * Erzeugt eine neue <code>OperationCanceledException</code>.
-   * @param mess Fehlermeldung
-   */
-  public OperationCanceledException(String mess) {
-    super(mess);
-  }
-}
+  /**
+   * Erzeugt eine neue <code>OperationCanceledException</code>.
+   * @param mess Fehlermeldung
+   */
+  public OperationCanceledException(String mess) {
+    super(mess);
+  }
+}

Modified: trunk/src/schmitzm/lang/PushbackStringTokenizer.java
===================================================================
--- trunk/src/schmitzm/lang/PushbackStringTokenizer.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/lang/PushbackStringTokenizer.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,136 +1,154 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.lang;
-
-import java.util.StringTokenizer;
-import java.util.Vector;
-
-/**
- * Diese Klasse erweitert den {@link StringTokenizer} um eine PushBack-Funktion,
- * mit der ein Token zurueck auf den Tokenizer gelegt werden kann.<br>
- * <b>Bemerkung:</b><br>
- * Solange noch Token im Pushback-Speicher liegen, liefert die Methode
- * {@link #nextToken(String)} eines diese Token, <u>ungeachtet</u> von den
- * dieser Methode uebergebenen Delimitern!
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class PushbackStringTokenizer extends StringTokenizer {
-  /** Verwaltet die bereits gelesenen Tokens. */
-  protected Vector<String> readTokens = new Vector<String>();
-
-  /** Verwaltet die zurueck gelegten Token. */
-  protected Vector<String> pushedbackTokens = new Vector<String>();
-
-  /**
-   * Erzeugt einen neuen Tokenizer.
-   * @param str          zu parsender String
-   * @param delim        Delimiter
-   * @param returnDelims bestimmt, ob die Delimiter ebenfalls als Token
-   *                     zurueckgeliefert werden
-   */
-  public PushbackStringTokenizer(String str, String delim,  boolean returnDelims) {
-    super(str, delim, returnDelims);
-  }
-
-  /**
-   * Erzeugt einen neuen Tokenizer. Die Delimiter werden nicht als Token
-   * zurueckgegeben.
-   * @param str   zu parsender String
-   * @param delim Delimiter
-   */
-  public PushbackStringTokenizer(String str, String delim) {
-    super(str, delim);
-  }
-
-  /**
-   * Erzeugt einen neuen Tokenizer. Als Delimiter werden {@code " \t\n\r\f"}
-   * verwendet. Diese werden nicht als Token interpretiert.
-   * zurueckgegeben.
-   * @param str zu parsender String
-   */
-  public PushbackStringTokenizer(String str) {
-    super(str);
-  }
-
-  /**
-   * Prueft, ob noch Tokens gelesen werden koennen.
-   */
-  public boolean hasMoreTokens() {
-    return !pushedbackTokens.isEmpty() || super.hasMoreTokens();
-  }
-
-  /**
-   * Liefert das naechste Token.
-   */
-  public String nextToken() {
-    String token = !pushedbackTokens.isEmpty() ? pushedbackTokens.remove(0) : super.nextToken();
-    readTokens.add(0,token);
-    return token;
-  }
-
-  /**
-   * Liefert das naechste Token.<br>
-   * <b>Diese Methode ist nur mit Bedacht zu verwenden, da sie - sofern vorhanden -
-   * das letzte mittels {@link #pushback()} zurueckgelegte Token liefert, egal
-   * welcher Delimiter uebergeben wurde!!</b>
-   * @param delim Delimiter fuer das naechste Token
-   */
-  public String nextToken(String delim) {
-    String token = !pushedbackTokens.isEmpty() ? pushedbackTokens.remove(0) : super.nextToken(delim);
-    readTokens.add(0,token);
-    return token;
-  }
-
-  /**
-   * Liefert denselben Wert wie {@link #hasMoreTokens()}.
-   */
-  public boolean hasMoreElements() {
-    return hasMoreTokens();
-  }
-
-  /**
-   * Liefert denselben Wert wie {@link #nextToken()}.
-   */
-  public Object nextElement() {
-    return nextToken();
-  }
-
-  /**
-   * Liefert die Anzahl an Token, die noch gelesen werden koennen.
-   */
-  public int countTokens() {
-    return pushedbackTokens.size() + super.countTokens();
-  }
-
-  /**
-   * Legt das zuletzt gelesene Token zurueck in den Tokenizer.
-   * @return das zurueckgelegte Token
-   */
-  public String pushback() {
-    String pushbackedToken = readTokens.remove(0);
-    pushedbackTokens.add(0, pushbackedToken );
-    return pushbackedToken;
-  }
-
-  /**
-   * Liefert alle bisher gelesenen Token als Zeichenkette. Diese Methode macht
-   * nur Sinn, wenn auch die Delimiter als Token gelesen werden.
-   */
-  public String getReadTokens() {
-    StringBuffer buffer = new StringBuffer();
-    for (int i=readTokens.size()-1; i>=0; i--)
-      buffer.append(readTokens.elementAt(i));
-    return buffer.toString();
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.lang;
+
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+/**
+ * Diese Klasse erweitert den {@link StringTokenizer} um eine PushBack-Funktion,
+ * mit der ein Token zurueck auf den Tokenizer gelegt werden kann.<br>
+ * <b>Bemerkung:</b><br>
+ * Solange noch Token im Pushback-Speicher liegen, liefert die Methode
+ * {@link #nextToken(String)} eines diese Token, <u>ungeachtet</u> von den
+ * dieser Methode uebergebenen Delimitern!
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class PushbackStringTokenizer extends StringTokenizer {
+  /** Verwaltet die bereits gelesenen Tokens. */
+  protected Vector<String> readTokens = new Vector<String>();
+
+  /** Verwaltet die zurueck gelegten Token. */
+  protected Vector<String> pushedbackTokens = new Vector<String>();
+
+  /**
+   * Erzeugt einen neuen Tokenizer.
+   * @param str          zu parsender String
+   * @param delim        Delimiter
+   * @param returnDelims bestimmt, ob die Delimiter ebenfalls als Token
+   *                     zurueckgeliefert werden
+   */
+  public PushbackStringTokenizer(String str, String delim,  boolean returnDelims) {
+    super(str, delim, returnDelims);
+  }
+
+  /**
+   * Erzeugt einen neuen Tokenizer. Die Delimiter werden nicht als Token
+   * zurueckgegeben.
+   * @param str   zu parsender String
+   * @param delim Delimiter
+   */
+  public PushbackStringTokenizer(String str, String delim) {
+    super(str, delim);
+  }
+
+  /**
+   * Erzeugt einen neuen Tokenizer. Als Delimiter werden {@code " \t\n\r\f"}
+   * verwendet. Diese werden nicht als Token interpretiert.
+   * zurueckgegeben.
+   * @param str zu parsender String
+   */
+  public PushbackStringTokenizer(String str) {
+    super(str);
+  }
+
+  /**
+   * Prueft, ob noch Tokens gelesen werden koennen.
+   */
+  public boolean hasMoreTokens() {
+    return !pushedbackTokens.isEmpty() || super.hasMoreTokens();
+  }
+
+  /**
+   * Liefert das naechste Token.
+   */
+  public String nextToken() {
+    String token = !pushedbackTokens.isEmpty() ? pushedbackTokens.remove(0) : super.nextToken();
+    readTokens.add(0,token);
+    return token;
+  }
+
+  /**
+   * Liefert das naechste Token.<br>
+   * <b>Diese Methode ist nur mit Bedacht zu verwenden, da sie - sofern vorhanden -
+   * das letzte mittels {@link #pushback()} zurueckgelegte Token liefert, egal
+   * welcher Delimiter uebergeben wurde!!</b>
+   * @param delim Delimiter fuer das naechste Token
+   */
+  public String nextToken(String delim) {
+    String token = !pushedbackTokens.isEmpty() ? pushedbackTokens.remove(0) : super.nextToken(delim);
+    readTokens.add(0,token);
+    return token;
+  }
+
+  /**
+   * Liefert denselben Wert wie {@link #hasMoreTokens()}.
+   */
+  public boolean hasMoreElements() {
+    return hasMoreTokens();
+  }
+
+  /**
+   * Liefert denselben Wert wie {@link #nextToken()}.
+   */
+  public Object nextElement() {
+    return nextToken();
+  }
+
+  /**
+   * Liefert die Anzahl an Token, die noch gelesen werden koennen.
+   */
+  public int countTokens() {
+    return pushedbackTokens.size() + super.countTokens();
+  }
+
+  /**
+   * Legt das zuletzt gelesene Token zurueck in den Tokenizer.
+   * @return das zurueckgelegte Token
+   */
+  public String pushback() {
+    String pushbackedToken = readTokens.remove(0);
+    pushedbackTokens.add(0, pushbackedToken );
+    return pushbackedToken;
+  }
+
+  /**
+   * Liefert alle bisher gelesenen Token als Zeichenkette. Diese Methode macht
+   * nur Sinn, wenn auch die Delimiter als Token gelesen werden.
+   */
+  public String getReadTokens() {
+    StringBuffer buffer = new StringBuffer();
+    for (int i=readTokens.size()-1; i>=0; i--)
+      buffer.append(readTokens.elementAt(i));
+    return buffer.toString();
+  }
+
+}

Modified: trunk/src/schmitzm/lang/ResourceProvider.java
===================================================================
--- trunk/src/schmitzm/lang/ResourceProvider.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/lang/ResourceProvider.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,459 +1,478 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.lang;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.PrintWriter;
-import java.net.URISyntaxException;
-import java.net.URL;
-import java.util.Locale;
-import java.util.MissingResourceException;
-import java.util.ResourceBundle;
-import java.util.Set;
-import java.util.SortedSet;
-import java.util.TreeSet;
-
-import org.apache.log4j.Logger;
-
-import schmitzm.jfree.JFreeChartUtil;
-
-/**
- * Stellt den Zugriff auf ein {@link ResourceBundle} zur Verfuegung.
- * Hierbei muss der Name (Pfad) ein standard-maessig verwendeten Bundles
- * angebenen werden. Es besteht die Moeglichkeit, dass fehlende Ressourcen
- * nicht mit einer {@link MissingResourceException} behandelt werden, sondern
- * mit <code>null</code>, bzw. einem Alternativ-String ignoriert werden.<br>
- * Zudem erlaubt es der {@code ResourceProvider}, dass ein alternatives
- * Resource-Bundle spezifiziert wird ({@link #resetResourceBundle(String,String) resetResourceBundle(..)}).
- * Ist dieses gesetzt, wird primaer darin nach einer Ressource gesucht. Nur wenn
- * dort die Ressource nicht gefunden wird, wird auf das Standard-Bundle
- * zurueckgegriffen.<br>
- * <br>
- * <b>Anwendungsbereich:</b><br>
- * Diverse Standard-Libraries stellen jeweils einen eigenen {@link ResourceProvider}
- * zur Verfuegung, dessen Bundle im Pfad des Standard-Library hinterlegt ist (z.B.
- * {@link JFreeChartUtil#RESOURCE}: Ressourcen hinterlegt in
- * {@code schmitzm.jfree.ResourceBundle_XXX.properties}).<br>
- * Sollen fuer eine spezielle Applikation diese Ressourcen (u.U. nur teilweise)
- * abgeaendert oder fuer eine neue Sprache erweitert werden, kann dies geschehen,
- * ohne Zugriff auf die Standard-Library zu haben. Die Applikation kann
- * einfach {@link #resetResourceBundle(String,String) resetResourceBundle(..)}
- * aufrufen und so den Resource-Provider anweisen, zunaechst ein applikationsspezifisches
- * Bundle zu verwenden (welches in einem appl.spez. Pfad hinterlegt ist).
- * Alle Library-internen Zugriffe werden durch den {@code ResourceProvider}
- * umgelenkt. Wenn das appl.spez. Bundle eine Ressource nicht zur Verfuegung stellt,
- * wird automatisch auf das Standard-Bundle zurueck gegriffen.
- * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class ResourceProvider {
-	private static final Logger LOGGER = Logger.getLogger(ResourceProvider.class.getSimpleName());
-	
-	/** Diese String constante wird zurückgeliefert, wenn keine Wert fuer den
-	 * Schluessel gefunden wurde. */
-	public static final String MISSING_RESOURCE_STRING = "???";
-
-  /** Standard-Resource-Bundle, auf das zurueckgegriffen wird, wenn
-   *  Ressource im aktuell gesetzten Bundle nicht gefunden wird. */
-  private String defaultResourceBundle = null;
-  /** Alternatives Resource-Bundle, in dem zuerst nach einer
-   *  Ressource gesucht wird. */
-  private String resourceBundle = defaultResourceBundle;
-  /** Prefix, das beim Suchen im alternativen Resource-Bundle jedem Key
-   *  vorangestellt wird. */
-  private String keyPrefix = "";
-  /** Flag, ob fehlende Ressourcen ignoriert werden, oder mit einer
-   *  {@link MissingResourceException} behandelt werden. */
-  private boolean ignoreMissingResource = false;
-  /** Wenn fehlende Ressourcen ignoriert werden, liefert {@link #getObject(String)}
-   *  den Wert {@code null}. {@link #getString(String)} liefert den in dieser
-   *  Variable hinterlegten Alternativ-String. */
-  private String  missingResourceString = null;
-  /** Sprache, die durch das Root-Bundle (Fallback-Bundle) dargestellt wird.
-   *  Nur zu Informationszwecken! */
-  private Locale rootLocale = null;
-
-  /**
-   * Erzeugt neuen neuen Resource-Provider mit dem Namen "ResourceBundle".
-   * Fehlende Ressourcen werden ignoriert und mit {@code null} oder MISSING_RESOURCE_STRING ("???")
-   * als Alternativ-String behandelt.
-   * @param defaultResourceBundle Name des Standard Resource-Bundle
-   * @param rootLocale Sprache des Root-Bundles
-   */
-  public ResourceProvider(Class clazz, Locale rootLocale) {
-    this(clazz, rootLocale, true);
-  }
-
-  /**
-   * Erzeugt neuen neuen Resource-Provider mit dem Namen "ResourceBundle".
-   * Wenn fehlende Ressourcen ignoriert werden, wird MISSING_RESOURCE_STRING ("???") als Alternativ-String
-   * verwendet.
-   * @param clazz                 Bestimmt das Package in dem das Bundle "RessourceBundle"
-   *                              gesucht wird
-   * @param rootLocale            Sprache des Root-Bundles
-   * @param ignoreMissingResource bestimmt, ob fehlende Ressourcen ignoriert werden
-   *                              oder mit einer {@link MissingResourceException}
-   *                              behandelt werden
-   */
-  public ResourceProvider(Class clazz, Locale rootLocale, boolean ignoreMissingResource) {
-    this(clazz,rootLocale,ignoreMissingResource,MISSING_RESOURCE_STRING);
-  }
-
-  /**
-   * Erzeugt neuen neuen Resource-Provider mit dem Namen "ResourceBundle".
-   * @param clazz                 Bestimmt das Package in dem das Bundle "RessourceBundle"
-   *                              gesucht wird
-   * @param rootLocale            Sprache des Root-Bundles
-   * @param ignoreMissingResource bestimmt, ob fehlende Ressourcen ignoriert werden
-   *                              oder mit einer {@link MissingResourceException}
-   *                              behandelt werden
-   * @param missingResourceString Alternativ-String der - wenn fehlende Ressourcen
-   *                              ignoriert werden - von {@link #getString(String)}
-   *                              zurueckgegeben wird
-   */
-  public ResourceProvider(Class clazz, Locale rootLocale, boolean ignoreMissingResource, String missingResourceString) {
-    this(clazz.getPackage().getName()+".ResourceBundle",rootLocale,ignoreMissingResource,missingResourceString);
-  }
-
-  /**
-   * Erzeugt neuen neuen Resource-Provider.
-   * Fehlende Ressourcen werden ignoriert und mit {@code null} oder MISSING_RESOURCE_STRING ("???")
-   * als Alternativ-String behandelt.
-   * @param defaultResourceBundle Name des Standard Resource-Bundle
-   * @param rootLocale            Sprache des Root-Bundles
-   */
-  public ResourceProvider(String defaultResourceBundle, Locale rootLocale) {
-    this(defaultResourceBundle,rootLocale,true);
-  }
-
-  /**
-   * Erzeugt neuen neuen Resource-Provider. Wenn fehlende Ressourcen
-   * ignoriert werden, wird MISSING_RESOURCE_STRING ("???") als Alternativ-String verwendet.
-   * @param defaultResourceBundle Name des Standard Resource-Bundle
-   * @param rootLocale            Sprache des Root-Bundles
-   * @param ignoreMissingResource bestimmt, ob fehlende Ressourcen ignoriert werden
-   *                              oder mit einer {@link MissingResourceException}
-   *                              behandelt werden
-   */
-  public ResourceProvider(String defaultResourceBundle, Locale rootLocale, boolean ignoreMissingResource) {
-    this(defaultResourceBundle,rootLocale,ignoreMissingResource,MISSING_RESOURCE_STRING);
-  }
-
-  /**
-   * Erzeugt neuen neuen Resource-Provider.
-   * @param defaultResourceBundle Name des Standard Resource-Bundle
-   * @param rootLocale            Sprache des Root-Bundles
-   * @param ignoreMissingResource bestimmt, ob fehlende Ressourcen ignoriert werden
-   *                              oder mit einer {@link MissingResourceException}
-   *                              behandelt werden
-   * @param missingResourceString Alternativ-String der - wenn fehlende Ressourcen
-   *                              ignoriert werden - von {@link #getString(String)}
-   *                              zurueckgegeben wird
-   */
-  public ResourceProvider(String defaultResourceBundle, Locale rootLocale, boolean ignoreMissingResource, String missingResourceString) {
-    this.defaultResourceBundle = defaultResourceBundle;
-    this.rootLocale            = rootLocale;
-    this.resourceBundle        = null;
-    this.ignoreMissingResource = ignoreMissingResource;
-    this.missingResourceString = missingResourceString;
-  }
-
-  /**
-   * Liefert den Namen des Bundles.
-   * @see #getBundleName()
-   */
-  public String toString() {
-    return getBundleName();
-  }
-
-  /**
-   * Liefert alle Keys unter denen eine Ressource hinterlegt ist.
-   */
-  public SortedSet<String> getKeys() {
-    String prefix = (keyPrefix != null) ? keyPrefix.trim() : "";
-    if ( !keyPrefix.equals("") )
-      prefix += ".";
-
-    SortedSet<String> keys = new TreeSet<String>();
-    // Alle Keys aus dem Alternativ-Bundle in die Key-Menge aufnehmen, die
-    // mit dem Preafix beginnen
-    try {
-      if ( resourceBundle != null )
-        for ( String key : ResourceBundle.getBundle(resourceBundle).keySet() )
-          if ( key.startsWith(prefix) )
-            keys.add( key.substring(prefix.length()) );
-    } catch (MissingResourceException err) {
-      // Es gibt kein Root-Bundle fuer das Alternativ-Bundle
-      // --> Keys im Alternativ-Bundle ignorieren
-    }
-    // Alle Keys aus dem Standard-Bundle um das Praefix erweitern un
-    // in die Key-Menge aufnehmen
-    for ( String key : ResourceBundle.getBundle(defaultResourceBundle).keySet() )
-      keys.add(key);
-
-    return keys;
-  }
-
-  /**
-   * Prueft, ob fehlende Ressourcen ignoriert werden (mit {@code null} oder
-   * Alternativ-String) oder ob eine {@link MissingResourceException}
-   * geworfen wird.
-   */
-  public boolean isMissingResourceIgnored() {
-    return ignoreMissingResource;
-  }
-
-  /**
-   * Bestimmt, ob fehlende Ressourcen ignoriert werden (mit {@code null} oder
-   * Alternativ-String) oder ob eine {@link MissingResourceException}
-   * geworfen wird.
-   */
-  public void setIgnoreMissingResource(boolean ignoreMissingResource) {
-    this.ignoreMissingResource = ignoreMissingResource;
-  }
-
-  /**
-   * Liefert den Alternativ-String, der beim Ignorieren fehlender
-   * Ressourcen von {@link getString(String)} zurueckgegeben wird.
-   */
-  public String getMissingResourceString() {
-    return missingResourceString;
-  }
-
-  /**
-   * Setzt den Alternativ-String, der beim Ignorieren fehlender
-   * Ressourcen von {@link getString(String)} zurueckgegeben wird.
-   */
-  public void setMissingResourceString(String missingResourceString) {
-    this.missingResourceString = missingResourceString;
-  }
-
-  /**
-   * Liefert ein Objekt aus dem Resource-Bundle. Wenn gesetzt, wird zunaechst im
-   * alternativen Bundle (ggf. mit Prefix) gesucht. Wenn die Ressource dort
-   * nicht gefunden wird, wird auf das Standard-Bundle zurueckgegriffen.
-   * Wenn die Suche (auch) dort nicht erfolgreich ist, wird je nach Einstellung
-   * eine {@link MissingResourceException} geworfen oder {@code null} zurueck
-   * gegeben.
-   * @param key Key unter dem der String gesucht wird
-   */
-  public Object getObject(String key) {
-    String primaryBundle = null;
-    String prefix        = "";
-    // Wenn gesetzt, dann das alternative Bundle (mit Key-Prefix)
-    // verwenden. Ansonsten das Standard-Bundle ohne Prefix.
-    if ( resourceBundle != null ) {
-      primaryBundle = resourceBundle;
-      prefix        = (keyPrefix != null && !keyPrefix.trim().equals("")) ? keyPrefix+"." : "";
-    } else {
-      primaryBundle = defaultResourceBundle;
-      prefix        =  "";
-    }
-
-    try {
-      // Ressource im gesetzten Bundle suchen
-      return ResourceBundle.getBundle(primaryBundle).getObject(prefix+key);
-    } catch (MissingResourceException err) {
-      // Ressource im Standard-Bundle suchen
-      try {
-        return ResourceBundle.getBundle(defaultResourceBundle).getObject(key);
-      } catch (MissingResourceException err2) {
-        // Wenn Ressource auch im Standard-Bundle nicht vorhanden ist,
-        // Fehler werfen (oder ignorieren
-        if ( ignoreMissingResource ) {
-          LOGGER.warn("ResourceBundle "+primaryBundle+": "+err.getMessage());
-          return null;
-        }
-        throw err2;
-      }
-    }
-  }
-
-  /**
-   * Liefert einen String aus dem Resource-Bundle. Wenn gesetzt, wird zunaechst im
-   * alternativen Bundle (ggf. mit Prefix) gesucht. Wenn die Ressource dort
-   * nicht gefunden wird, wird auf das Standard-Bundle zurueckgegriffen.
-   * Wenn die Suche (auch) dort nicht erfolgreich ist, wird je nach Einstellung
-   * eine {@link MissingResourceException} geworfen oder der Alternativ-String
-   * zurueck gegeben.
-   * @param key Key unter dem der String gesucht wird
-   * @param replParams Strings/Zahlen, mit denen die im String enthaltenen
-   *                   Wildcards <code>${0}</code>, <code>${1}</code>, <code>${2}</code>, usw.
-   *                   ersetzt werden (sehr hilfreich z.B. fuer lokalisierte
-   *                   Fehlermeldungen)
-   */
-  public String getString(String key, Object... replParams) {
-    Object object = getObject(key);
-    String string = object != null ? object.toString() : missingResourceString;
-    for (int i=0; i<replParams.length; i++)
-      string = string.replaceAll("\\$\\{"+i+"\\}", replParams[i] != null ? replParams[i].toString() : "null");
-    return string;
-  }
-
-  /**
-   * Setzt ein alternatives Resource-Bundle, in welchem als erstes nach
-   * einer Ressource gesucht wird. Dieses sollte die gleiche Fall-Back-Sprache
-   * haben, wie das Standard-Bundle.
-   * @param bundle String
-   * @param keyPrefix Prefix, welches bei der Suche im alternativen Bundle
-   *                  automatisch jedem Key vorangestellt wird
-   */
-  public void resetResourceBundle(String bundle, String keyPrefix) {
-    this.resourceBundle = bundle;
-    this.keyPrefix      = keyPrefix;
-  }
-
-  /**
-   * Setzt ein alternatives Resource-Bundle, in welchem als erstes nach
-   * einer Ressource gesucht wird. Dieses sollte die gleiche Fall-Back-Sprache
-   * haben, wie das Standard-Bundle. Ein Key-Prefix wird nicht verwendet.
-   * @param bundle String
-   */
-  public void resetResourceBundle(String bundle) {
-    resetResourceBundle(bundle,null);
-  }
-
-  /**
-   * Entfernt das alternative Resource-Bundle, so dass im folgenden immer
-   * direkt im Standard-Bundle gesucht wird.
-   */
-  public void resetResourceBundle() {
-    resetResourceBundle(null,null);
-  }
-
-  /**
-   * Liefert das Prefix, das im Alternativ-Bundle jedem Key vorangestellt
-   * ist.
-   */
-  public String getKeyPrefix() {
-    return keyPrefix;
-  }
-
-  /**
-   * Liefert den Namen des Resource-Bundle. Wenn ein Alternativ-Bundle gesetzt
-   * wurde, wird dessen Name zurueckgegeben.
-   */
-  public String getBundleName() {
-    return resourceBundle == null ? defaultResourceBundle : resourceBundle;
-  }
-
-  /**
-   * Liefert den Namen des Standard-Resource-Bundle.
-   */
-  public String getDefaultBundleName() {
-    return defaultResourceBundle;
-  }
-
-  /**
-   * Liefert die Standard-Sprache des Resource-Bundles ("Fall-Back").
-   */
-  public Locale getRootLocale() {
-    return rootLocale;
-  }
-
-  /**
-   * Liefert alle Sprachen, die der {@code ResourceProvider} zur Verfuegung
-   * stellt.
-   * @param inclRootLocale   wenn {@link false} wird die "Fall-Back"-Sprache
-   *                         nicht beruecksichtigt
-   */
-  public Set<Locale> getAvailableLocales(boolean inclRootLocale) {
-    return getAvailableLocales(this,inclRootLocale);
-  }
-
-
-  /**
-   * Liefert alle Sprachen, die ein {@link ResourceProvider} zur Verfuegung
-   * stellt.
-   * @param resourceProvider ResourceProvider
-   * @param inclRootLocale   wenn {@link false} wird die "Fall-Back"-Sprache
-   *                         nicht beruecksichtigt
-   */
-  public static Set<Locale> getAvailableLocales(ResourceProvider resourceProvider, boolean inclRootLocale) {
-    Set<Locale> avLocales = new TreeSet<Locale>(new LocaleComparator(true));
-    if ( inclRootLocale && resourceProvider.getRootLocale() != null )
-      avLocales.add( resourceProvider.getRootLocale() );
-
-    // leider sehe ich keine andere Moeglichkeit, als "alle Sprachen"
-    // durchzuprobieren...
-    for ( Locale l : Locale.getAvailableLocales() ) {
-      if ( checkLocaleAvailable( resourceProvider.getDefaultBundleName(),l ) ||
-           checkLocaleAvailable( resourceProvider.getBundleName(),l ) )
-        avLocales.add(l);
-    }
-    return avLocales;
-  }
-
-  private static boolean checkLocaleAvailable(String bundleName, Locale l) {
-    try {
-      return l != null && l.equals( ResourceBundle.getBundle(bundleName,l).getLocale() );
-    } catch (Exception err) {
-    }
-    return false;
-  }
-
-  /**
-   * Liefert die Property-Datei ({@code .properties}) fuer ein Resource Bundle.
-   * @param provider Resource-Provider fuer den das neue Bundle angelegt wird
-   * @param l Sprache des neuen Bundles
-   * @exception URISyntaxException wenn bei der Ermittlung des Datei-Pfads
-   *            ein Fehler auftritt
-   */
-  public static File getPropertyFile(ResourceProvider provider, Locale l) throws URISyntaxException{
-    String bundlePath       = provider.getBundleName();
-    int    lastDotIdx       = bundlePath.lastIndexOf(".");
-    String bundleName       = bundlePath.substring(lastDotIdx+1);
-    String bundlePackage    = bundlePath.substring(0, lastDotIdx).replace(".","/");
-    URL    bundlePackageURL = ClassLoader.getSystemResource(bundlePackage);
-    String newBundleName    = bundleName + "_" + l.toString() + ".properties";
-    File   newBundleFile    = new File(new File(bundlePackageURL.toURI()),newBundleName);
-    return newBundleFile;
-  }
-
-  /**
-   * Erzeugt eine Property-Datei ({@code .properties}) fuer ein Resource Bundle.
-   * In dieser sind bereits alle Keys des Bundles enthalten und mit einem Dummy-Wert
-   * vorbelegt.
-   * @param provider Resource-Provider fuer den das neue Bundle angelegt wird
-   * @param l Sprache des neuen Bundles
-   * @param append wenn {@code true}, wird eine bestehende Datei erweitert,
-   *               andernfalls ueberschrieben
-   */
-  public static void createPropertyFile(ResourceProvider provider, Locale l, boolean append) throws URISyntaxException, FileNotFoundException {
-    File        newBundleFile = getPropertyFile(provider,l);
-    PrintWriter out           = new PrintWriter( new FileOutputStream(newBundleFile, append) );
-    // Wenn Datei neu angelegt wird, wird ein Header erstellt
-    if ( !newBundleFile.exists() || newBundleFile.length() == 0 ) {
-      out.println("# ----------------------------------------------------------------------------------");
-      out.println("#  LANGUAGE: "+l.toString()+" = "+l.getDisplayLanguage());
-      out.println("# ----------------------------------------------------------------------------------");
-    }
-    out.println("# Original bundle: "+provider.getDefaultBundleName());
-
-    // etwaiges Key-Prefix ermitteln
-    String prefix = provider.getKeyPrefix();
-    if ( prefix == null )
-      prefix = "";
-    if ( !prefix.equals("") )
-      prefix += ".";
-
-    // Keys mit Dummy-Werten in Datei schreiben
-    for (String key : provider.getKeys())
-      out.println(prefix+key+"=?"+l.toString()+"? "+provider.getString(key));
-    out.println("# ----------------------------------------------------------------------------------");
-    out.flush();
-    out.close();
-  }
-
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.lang;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintWriter;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.util.Locale;
+import java.util.MissingResourceException;
+import java.util.ResourceBundle;
+import java.util.Set;
+import java.util.SortedSet;
+import java.util.TreeSet;
+
+import org.apache.log4j.Logger;
+
+import schmitzm.jfree.JFreeChartUtil;
+
+/**
+ * Stellt den Zugriff auf ein {@link ResourceBundle} zur Verfuegung.
+ * Hierbei muss der Name (Pfad) ein standard-maessig verwendeten Bundles
+ * angebenen werden. Es besteht die Moeglichkeit, dass fehlende Ressourcen
+ * nicht mit einer {@link MissingResourceException} behandelt werden, sondern
+ * mit <code>null</code>, bzw. einem Alternativ-String ignoriert werden.<br>
+ * Zudem erlaubt es der {@code ResourceProvider}, dass ein alternatives
+ * Resource-Bundle spezifiziert wird ({@link #resetResourceBundle(String,String) resetResourceBundle(..)}).
+ * Ist dieses gesetzt, wird primaer darin nach einer Ressource gesucht. Nur wenn
+ * dort die Ressource nicht gefunden wird, wird auf das Standard-Bundle
+ * zurueckgegriffen.<br>
+ * <br>
+ * <b>Anwendungsbereich:</b><br>
+ * Diverse Standard-Libraries stellen jeweils einen eigenen {@link ResourceProvider}
+ * zur Verfuegung, dessen Bundle im Pfad des Standard-Library hinterlegt ist (z.B.
+ * {@link JFreeChartUtil#RESOURCE}: Ressourcen hinterlegt in
+ * {@code schmitzm.jfree.ResourceBundle_XXX.properties}).<br>
+ * Sollen fuer eine spezielle Applikation diese Ressourcen (u.U. nur teilweise)
+ * abgeaendert oder fuer eine neue Sprache erweitert werden, kann dies geschehen,
+ * ohne Zugriff auf die Standard-Library zu haben. Die Applikation kann
+ * einfach {@link #resetResourceBundle(String,String) resetResourceBundle(..)}
+ * aufrufen und so den Resource-Provider anweisen, zunaechst ein applikationsspezifisches
+ * Bundle zu verwenden (welches in einem appl.spez. Pfad hinterlegt ist).
+ * Alle Library-internen Zugriffe werden durch den {@code ResourceProvider}
+ * umgelenkt. Wenn das appl.spez. Bundle eine Ressource nicht zur Verfuegung stellt,
+ * wird automatisch auf das Standard-Bundle zurueck gegriffen.
+ * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class ResourceProvider {
+	private static final Logger LOGGER = Logger.getLogger(ResourceProvider.class.getSimpleName());
+	
+	/** Diese String constante wird zurückgeliefert, wenn keine Wert fuer den
+	 * Schluessel gefunden wurde. */
+	public static final String MISSING_RESOURCE_STRING = "???";
+
+  /** Standard-Resource-Bundle, auf das zurueckgegriffen wird, wenn
+   *  Ressource im aktuell gesetzten Bundle nicht gefunden wird. */
+  private String defaultResourceBundle = null;
+  /** Alternatives Resource-Bundle, in dem zuerst nach einer
+   *  Ressource gesucht wird. */
+  private String resourceBundle = defaultResourceBundle;
+  /** Prefix, das beim Suchen im alternativen Resource-Bundle jedem Key
+   *  vorangestellt wird. */
+  private String keyPrefix = "";
+  /** Flag, ob fehlende Ressourcen ignoriert werden, oder mit einer
+   *  {@link MissingResourceException} behandelt werden. */
+  private boolean ignoreMissingResource = false;
+  /** Wenn fehlende Ressourcen ignoriert werden, liefert {@link #getObject(String)}
+   *  den Wert {@code null}. {@link #getString(String)} liefert den in dieser
+   *  Variable hinterlegten Alternativ-String. */
+  private String  missingResourceString = null;
+  /** Sprache, die durch das Root-Bundle (Fallback-Bundle) dargestellt wird.
+   *  Nur zu Informationszwecken! */
+  private Locale rootLocale = null;
+
+  /**
+   * Erzeugt neuen neuen Resource-Provider mit dem Namen "ResourceBundle".
+   * Fehlende Ressourcen werden ignoriert und mit {@code null} oder MISSING_RESOURCE_STRING ("???")
+   * als Alternativ-String behandelt.
+   * @param defaultResourceBundle Name des Standard Resource-Bundle
+   * @param rootLocale Sprache des Root-Bundles
+   */
+  public ResourceProvider(Class clazz, Locale rootLocale) {
+    this(clazz, rootLocale, true);
+  }
+
+  /**
+   * Erzeugt neuen neuen Resource-Provider mit dem Namen "ResourceBundle".
+   * Wenn fehlende Ressourcen ignoriert werden, wird MISSING_RESOURCE_STRING ("???") als Alternativ-String
+   * verwendet.
+   * @param clazz                 Bestimmt das Package in dem das Bundle "RessourceBundle"
+   *                              gesucht wird
+   * @param rootLocale            Sprache des Root-Bundles
+   * @param ignoreMissingResource bestimmt, ob fehlende Ressourcen ignoriert werden
+   *                              oder mit einer {@link MissingResourceException}
+   *                              behandelt werden
+   */
+  public ResourceProvider(Class clazz, Locale rootLocale, boolean ignoreMissingResource) {
+    this(clazz,rootLocale,ignoreMissingResource,MISSING_RESOURCE_STRING);
+  }
+
+  /**
+   * Erzeugt neuen neuen Resource-Provider mit dem Namen "ResourceBundle".
+   * @param clazz                 Bestimmt das Package in dem das Bundle "RessourceBundle"
+   *                              gesucht wird
+   * @param rootLocale            Sprache des Root-Bundles
+   * @param ignoreMissingResource bestimmt, ob fehlende Ressourcen ignoriert werden
+   *                              oder mit einer {@link MissingResourceException}
+   *                              behandelt werden
+   * @param missingResourceString Alternativ-String der - wenn fehlende Ressourcen
+   *                              ignoriert werden - von {@link #getString(String)}
+   *                              zurueckgegeben wird
+   */
+  public ResourceProvider(Class clazz, Locale rootLocale, boolean ignoreMissingResource, String missingResourceString) {
+    this(clazz.getPackage().getName()+".ResourceBundle",rootLocale,ignoreMissingResource,missingResourceString);
+  }
+
+  /**
+   * Erzeugt neuen neuen Resource-Provider.
+   * Fehlende Ressourcen werden ignoriert und mit {@code null} oder MISSING_RESOURCE_STRING ("???")
+   * als Alternativ-String behandelt.
+   * @param defaultResourceBundle Name des Standard Resource-Bundle
+   * @param rootLocale            Sprache des Root-Bundles
+   */
+  public ResourceProvider(String defaultResourceBundle, Locale rootLocale) {
+    this(defaultResourceBundle,rootLocale,true);
+  }
+
+  /**
+   * Erzeugt neuen neuen Resource-Provider. Wenn fehlende Ressourcen
+   * ignoriert werden, wird MISSING_RESOURCE_STRING ("???") als Alternativ-String verwendet.
+   * @param defaultResourceBundle Name des Standard Resource-Bundle
+   * @param rootLocale            Sprache des Root-Bundles
+   * @param ignoreMissingResource bestimmt, ob fehlende Ressourcen ignoriert werden
+   *                              oder mit einer {@link MissingResourceException}
+   *                              behandelt werden
+   */
+  public ResourceProvider(String defaultResourceBundle, Locale rootLocale, boolean ignoreMissingResource) {
+    this(defaultResourceBundle,rootLocale,ignoreMissingResource,MISSING_RESOURCE_STRING);
+  }
+
+  /**
+   * Erzeugt neuen neuen Resource-Provider.
+   * @param defaultResourceBundle Name des Standard Resource-Bundle
+   * @param rootLocale            Sprache des Root-Bundles
+   * @param ignoreMissingResource bestimmt, ob fehlende Ressourcen ignoriert werden
+   *                              oder mit einer {@link MissingResourceException}
+   *                              behandelt werden
+   * @param missingResourceString Alternativ-String der - wenn fehlende Ressourcen
+   *                              ignoriert werden - von {@link #getString(String)}
+   *                              zurueckgegeben wird
+   */
+  public ResourceProvider(String defaultResourceBundle, Locale rootLocale, boolean ignoreMissingResource, String missingResourceString) {
+    this.defaultResourceBundle = defaultResourceBundle;
+    this.rootLocale            = rootLocale;
+    this.resourceBundle        = null;
+    this.ignoreMissingResource = ignoreMissingResource;
+    this.missingResourceString = missingResourceString;
+  }
+
+  /**
+   * Liefert den Namen des Bundles.
+   * @see #getBundleName()
+   */
+  public String toString() {
+    return getBundleName();
+  }
+
+  /**
+   * Liefert alle Keys unter denen eine Ressource hinterlegt ist.
+   */
+  public SortedSet<String> getKeys() {
+    String prefix = (keyPrefix != null) ? keyPrefix.trim() : "";
+    if ( !keyPrefix.equals("") )
+      prefix += ".";
+
+    SortedSet<String> keys = new TreeSet<String>();
+    // Alle Keys aus dem Alternativ-Bundle in die Key-Menge aufnehmen, die
+    // mit dem Preafix beginnen
+    try {
+      if ( resourceBundle != null )
+        for ( String key : ResourceBundle.getBundle(resourceBundle).keySet() )
+          if ( key.startsWith(prefix) )
+            keys.add( key.substring(prefix.length()) );
+    } catch (MissingResourceException err) {
+      // Es gibt kein Root-Bundle fuer das Alternativ-Bundle
+      // --> Keys im Alternativ-Bundle ignorieren
+    }
+    // Alle Keys aus dem Standard-Bundle um das Praefix erweitern un
+    // in die Key-Menge aufnehmen
+    for ( String key : ResourceBundle.getBundle(defaultResourceBundle).keySet() )
+      keys.add(key);
+
+    return keys;
+  }
+
+  /**
+   * Prueft, ob fehlende Ressourcen ignoriert werden (mit {@code null} oder
+   * Alternativ-String) oder ob eine {@link MissingResourceException}
+   * geworfen wird.
+   */
+  public boolean isMissingResourceIgnored() {
+    return ignoreMissingResource;
+  }
+
+  /**
+   * Bestimmt, ob fehlende Ressourcen ignoriert werden (mit {@code null} oder
+   * Alternativ-String) oder ob eine {@link MissingResourceException}
+   * geworfen wird.
+   */
+  public void setIgnoreMissingResource(boolean ignoreMissingResource) {
+    this.ignoreMissingResource = ignoreMissingResource;
+  }
+
+  /**
+   * Liefert den Alternativ-String, der beim Ignorieren fehlender
+   * Ressourcen von {@link getString(String)} zurueckgegeben wird.
+   */
+  public String getMissingResourceString() {
+    return missingResourceString;
+  }
+
+  /**
+   * Setzt den Alternativ-String, der beim Ignorieren fehlender
+   * Ressourcen von {@link getString(String)} zurueckgegeben wird.
+   */
+  public void setMissingResourceString(String missingResourceString) {
+    this.missingResourceString = missingResourceString;
+  }
+
+  /**
+   * Liefert ein Objekt aus dem Resource-Bundle. Wenn gesetzt, wird zunaechst im
+   * alternativen Bundle (ggf. mit Prefix) gesucht. Wenn die Ressource dort
+   * nicht gefunden wird, wird auf das Standard-Bundle zurueckgegriffen.
+   * Wenn die Suche (auch) dort nicht erfolgreich ist, wird je nach Einstellung
+   * eine {@link MissingResourceException} geworfen oder {@code null} zurueck
+   * gegeben.
+   * @param key Key unter dem der String gesucht wird
+   */
+  public Object getObject(String key) {
+    String primaryBundle = null;
+    String prefix        = "";
+    // Wenn gesetzt, dann das alternative Bundle (mit Key-Prefix)
+    // verwenden. Ansonsten das Standard-Bundle ohne Prefix.
+    if ( resourceBundle != null ) {
+      primaryBundle = resourceBundle;
+      prefix        = (keyPrefix != null && !keyPrefix.trim().equals("")) ? keyPrefix+"." : "";
+    } else {
+      primaryBundle = defaultResourceBundle;
+      prefix        =  "";
+    }
+
+    try {
+      // Ressource im gesetzten Bundle suchen
+      return ResourceBundle.getBundle(primaryBundle).getObject(prefix+key);
+    } catch (MissingResourceException err) {
+      // Ressource im Standard-Bundle suchen
+      try {
+        return ResourceBundle.getBundle(defaultResourceBundle).getObject(key);
+      } catch (MissingResourceException err2) {
+        // Wenn Ressource auch im Standard-Bundle nicht vorhanden ist,
+        // Fehler werfen (oder ignorieren
+        if ( ignoreMissingResource ) {
+          LOGGER.warn("ResourceBundle "+primaryBundle+": "+err.getMessage());
+          return null;
+        }
+        throw err2;
+      }
+    }
+  }
+
+  /**
+   * Liefert einen String aus dem Resource-Bundle. Wenn gesetzt, wird zunaechst im
+   * alternativen Bundle (ggf. mit Prefix) gesucht. Wenn die Ressource dort
+   * nicht gefunden wird, wird auf das Standard-Bundle zurueckgegriffen.
+   * Wenn die Suche (auch) dort nicht erfolgreich ist, wird je nach Einstellung
+   * eine {@link MissingResourceException} geworfen oder der Alternativ-String
+   * zurueck gegeben.
+   * @param key Key unter dem der String gesucht wird
+   * @param replParams Strings/Zahlen, mit denen die im String enthaltenen
+   *                   Wildcards <code>${0}</code>, <code>${1}</code>, <code>${2}</code>, usw.
+   *                   ersetzt werden (sehr hilfreich z.B. fuer lokalisierte
+   *                   Fehlermeldungen)
+   */
+  public String getString(String key, Object... replParams) {
+    Object object = getObject(key);
+    String string = object != null ? object.toString() : missingResourceString;
+    for (int i=0; i<replParams.length; i++)
+      string = string.replaceAll("\\$\\{"+i+"\\}", replParams[i] != null ? replParams[i].toString() : "null");
+    return string;
+  }
+
+  /**
+   * Setzt ein alternatives Resource-Bundle, in welchem als erstes nach
+   * einer Ressource gesucht wird. Dieses sollte die gleiche Fall-Back-Sprache
+   * haben, wie das Standard-Bundle.
+   * @param bundle String
+   * @param keyPrefix Prefix, welches bei der Suche im alternativen Bundle
+   *                  automatisch jedem Key vorangestellt wird
+   */
+  public void resetResourceBundle(String bundle, String keyPrefix) {
+    this.resourceBundle = bundle;
+    this.keyPrefix      = keyPrefix;
+  }
+
+  /**
+   * Setzt ein alternatives Resource-Bundle, in welchem als erstes nach
+   * einer Ressource gesucht wird. Dieses sollte die gleiche Fall-Back-Sprache
+   * haben, wie das Standard-Bundle. Ein Key-Prefix wird nicht verwendet.
+   * @param bundle String
+   */
+  public void resetResourceBundle(String bundle) {
+    resetResourceBundle(bundle,null);
+  }
+
+  /**
+   * Entfernt das alternative Resource-Bundle, so dass im folgenden immer
+   * direkt im Standard-Bundle gesucht wird.
+   */
+  public void resetResourceBundle() {
+    resetResourceBundle(null,null);
+  }
+
+  /**
+   * Liefert das Prefix, das im Alternativ-Bundle jedem Key vorangestellt
+   * ist.
+   */
+  public String getKeyPrefix() {
+    return keyPrefix;
+  }
+
+  /**
+   * Liefert den Namen des Resource-Bundle. Wenn ein Alternativ-Bundle gesetzt
+   * wurde, wird dessen Name zurueckgegeben.
+   */
+  public String getBundleName() {
+    return resourceBundle == null ? defaultResourceBundle : resourceBundle;
+  }
+
+  /**
+   * Liefert den Namen des Standard-Resource-Bundle.
+   */
+  public String getDefaultBundleName() {
+    return defaultResourceBundle;
+  }
+
+  /**
+   * Liefert die Standard-Sprache des Resource-Bundles ("Fall-Back").
+   */
+  public Locale getRootLocale() {
+    return rootLocale;
+  }
+
+  /**
+   * Liefert alle Sprachen, die der {@code ResourceProvider} zur Verfuegung
+   * stellt.
+   * @param inclRootLocale   wenn {@link false} wird die "Fall-Back"-Sprache
+   *                         nicht beruecksichtigt
+   */
+  public Set<Locale> getAvailableLocales(boolean inclRootLocale) {
+    return getAvailableLocales(this,inclRootLocale);
+  }
+
+
+  /**
+   * Liefert alle Sprachen, die ein {@link ResourceProvider} zur Verfuegung
+   * stellt.
+   * @param resourceProvider ResourceProvider
+   * @param inclRootLocale   wenn {@link false} wird die "Fall-Back"-Sprache
+   *                         nicht beruecksichtigt
+   */
+  public static Set<Locale> getAvailableLocales(ResourceProvider resourceProvider, boolean inclRootLocale) {
+    Set<Locale> avLocales = new TreeSet<Locale>(new LocaleComparator(true));
+    if ( inclRootLocale && resourceProvider.getRootLocale() != null )
+      avLocales.add( resourceProvider.getRootLocale() );
+
+    // leider sehe ich keine andere Moeglichkeit, als "alle Sprachen"
+    // durchzuprobieren...
+    for ( Locale l : Locale.getAvailableLocales() ) {
+      if ( checkLocaleAvailable( resourceProvider.getDefaultBundleName(),l ) ||
+           checkLocaleAvailable( resourceProvider.getBundleName(),l ) )
+        avLocales.add(l);
+    }
+    return avLocales;
+  }
+
+  private static boolean checkLocaleAvailable(String bundleName, Locale l) {
+    try {
+      return l != null && l.equals( ResourceBundle.getBundle(bundleName,l).getLocale() );
+    } catch (Exception err) {
+    }
+    return false;
+  }
+
+  /**
+   * Liefert die Property-Datei ({@code .properties}) fuer ein Resource Bundle.
+   * @param provider Resource-Provider fuer den das neue Bundle angelegt wird
+   * @param l Sprache des neuen Bundles
+   * @exception URISyntaxException wenn bei der Ermittlung des Datei-Pfads
+   *            ein Fehler auftritt
+   */
+  public static File getPropertyFile(ResourceProvider provider, Locale l) throws URISyntaxException{
+    String bundlePath       = provider.getBundleName();
+    int    lastDotIdx       = bundlePath.lastIndexOf(".");
+    String bundleName       = bundlePath.substring(lastDotIdx+1);
+    String bundlePackage    = bundlePath.substring(0, lastDotIdx).replace(".","/");
+    URL    bundlePackageURL = ClassLoader.getSystemResource(bundlePackage);
+    String newBundleName    = bundleName + "_" + l.toString() + ".properties";
+    File   newBundleFile    = new File(new File(bundlePackageURL.toURI()),newBundleName);
+    return newBundleFile;
+  }
+
+  /**
+   * Erzeugt eine Property-Datei ({@code .properties}) fuer ein Resource Bundle.
+   * In dieser sind bereits alle Keys des Bundles enthalten und mit einem Dummy-Wert
+   * vorbelegt.
+   * @param provider Resource-Provider fuer den das neue Bundle angelegt wird
+   * @param l Sprache des neuen Bundles
+   * @param append wenn {@code true}, wird eine bestehende Datei erweitert,
+   *               andernfalls ueberschrieben
+   */
+  public static void createPropertyFile(ResourceProvider provider, Locale l, boolean append) throws URISyntaxException, FileNotFoundException {
+    File        newBundleFile = getPropertyFile(provider,l);
+    PrintWriter out           = new PrintWriter( new FileOutputStream(newBundleFile, append) );
+    // Wenn Datei neu angelegt wird, wird ein Header erstellt
+    if ( !newBundleFile.exists() || newBundleFile.length() == 0 ) {
+      out.println("# ----------------------------------------------------------------------------------");
+      out.println("#  LANGUAGE: "+l.toString()+" = "+l.getDisplayLanguage());
+      out.println("# ----------------------------------------------------------------------------------");
+    }
+    out.println("# Original bundle: "+provider.getDefaultBundleName());
+
+    // etwaiges Key-Prefix ermitteln
+    String prefix = provider.getKeyPrefix();
+    if ( prefix == null )
+      prefix = "";
+    if ( !prefix.equals("") )
+      prefix += ".";
+
+    // Keys mit Dummy-Werten in Datei schreiben
+    for (String key : provider.getKeys())
+      out.println(prefix+key+"=?"+l.toString()+"? "+provider.getString(key));
+    out.println("# ----------------------------------------------------------------------------------");
+    out.flush();
+    out.close();
+  }
+
+
+}

Modified: trunk/src/schmitzm/lang/SortableVector.java
===================================================================
--- trunk/src/schmitzm/lang/SortableVector.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/lang/SortableVector.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,126 +1,144 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.lang;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.Vector;
-
-/**
- * Diese Klasse erweitert den {@linkplain Vector Java-Vector} um eine
- * Sortier-Funktion.
- * Die Elemente werden (aus Effizienzgruenden) <b>nicht</b> automatisch
- * sortiert. Ein Aufruf von {@link #sort()} oder {@link #sortInverted()} ist
- * hierfuer notwendig.
- * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class SortableVector<E> extends Vector<E> {
-  /** {@link Comparator}, der die Sortierung bestimmt. */
-  protected Comparator comparator = null;
-  /** {@link Comparator}, der die invertierte Sortierung bestimmt. */
-  protected Comparator invertedComparator = null;
-
-  /**
-   * Erzeugt einen neuen {@code SortableVector}. Es wird der
-   * {@link DefaultComparator} verwendet.
-   */
-  public SortableVector(int initialCapacity, int capacityIncrement) {
-    this(null,initialCapacity, capacityIncrement);
-  }
-
-  /**
-   * Erzeugt einen neuen {@code SortableVector}. Es wird der
-   * {@link DefaultComparator} verwendet.
-   */
-  public SortableVector(int initialCapacity) {
-    this(null,initialCapacity);
-  }
-
-  /**
-   * Erzeugt einen neuen {@code SortableVector}. Es wird der
-   * {@link DefaultComparator} verwendet.
-   */
-  public SortableVector() {
-    this((Comparator)null);
-  }
-
-  /**
-   * Erzeugt einen neuen {@code SortableVector}. Es wird der
-   * {@link DefaultComparator} verwendet.
-   */
-  public SortableVector(Collection c) {
-    this(null, c);
-  }
-
-  /**
-   * Erzeugt einen neuen {@code SortableVector}
-   * @param comparator bestimmt die Sortierung
-   */
-  public SortableVector(Comparator comparator, int initialCapacity, int capacityIncrement) {
-    super(initialCapacity, capacityIncrement);
-    setComparator(comparator);
-  }
-
-  /**
-   * Erzeugt einen neuen {@code SortableVector}
-   * @param comparator bestimmt die Sortierung
-   */
-  public SortableVector(Comparator comparator, int initialCapacity) {
-    super(initialCapacity);
-    setComparator(comparator);
-  }
-
-  /**
-   * Erzeugt einen neuen {@code SortableVector}
-   * @param comparator bestimmt die Sortierung
-   */
-  public SortableVector(Comparator comparator) {
-    super();
-    setComparator(comparator);
-  }
-
-  /**
-   * Erzeugt einen neuen {@code SortableVector}
-   * @param comparator bestimmt die Sortierung
-   */
-  public SortableVector(Comparator comparator, Collection c) {
-    super(c);
-    setComparator(comparator);
-  }
-
-  /**
-   * Belegt die globale Variable {@link #comparator} mit einem neuen Wert.
-   * Wird {@code null} uebergeben, wird der {@link DefaultComparator} verwendet
-   * @param comparator ein Comparator
-   */
-  private void setComparator(Comparator comparator) {
-    this.comparator = (comparator != null) ? comparator : DefaultComparator.DEFAULT;
-    this.invertedComparator = DefaultComparator.invert(this.comparator);
-  }
-
-  /**
-   * Sortiert den Vector.
-   */
-  public void sort() {
-    Arrays.sort( this.elementData, comparator );
-  }
-
-  /**
-   * Sortiert den Vector in der umgekehrten Reihenfolge.
-   */
-  public void sortInverted() {
-    Arrays.sort( this.elementData, invertedComparator );
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.lang;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Vector;
+
+/**
+ * Diese Klasse erweitert den {@linkplain Vector Java-Vector} um eine
+ * Sortier-Funktion.
+ * Die Elemente werden (aus Effizienzgruenden) <b>nicht</b> automatisch
+ * sortiert. Ein Aufruf von {@link #sort()} oder {@link #sortInverted()} ist
+ * hierfuer notwendig.
+ * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class SortableVector<E> extends Vector<E> {
+  /** {@link Comparator}, der die Sortierung bestimmt. */
+  protected Comparator comparator = null;
+  /** {@link Comparator}, der die invertierte Sortierung bestimmt. */
+  protected Comparator invertedComparator = null;
+
+  /**
+   * Erzeugt einen neuen {@code SortableVector}. Es wird der
+   * {@link DefaultComparator} verwendet.
+   */
+  public SortableVector(int initialCapacity, int capacityIncrement) {
+    this(null,initialCapacity, capacityIncrement);
+  }
+
+  /**
+   * Erzeugt einen neuen {@code SortableVector}. Es wird der
+   * {@link DefaultComparator} verwendet.
+   */
+  public SortableVector(int initialCapacity) {
+    this(null,initialCapacity);
+  }
+
+  /**
+   * Erzeugt einen neuen {@code SortableVector}. Es wird der
+   * {@link DefaultComparator} verwendet.
+   */
+  public SortableVector() {
+    this((Comparator)null);
+  }
+
+  /**
+   * Erzeugt einen neuen {@code SortableVector}. Es wird der
+   * {@link DefaultComparator} verwendet.
+   */
+  public SortableVector(Collection c) {
+    this(null, c);
+  }
+
+  /**
+   * Erzeugt einen neuen {@code SortableVector}
+   * @param comparator bestimmt die Sortierung
+   */
+  public SortableVector(Comparator comparator, int initialCapacity, int capacityIncrement) {
+    super(initialCapacity, capacityIncrement);
+    setComparator(comparator);
+  }
+
+  /**
+   * Erzeugt einen neuen {@code SortableVector}
+   * @param comparator bestimmt die Sortierung
+   */
+  public SortableVector(Comparator comparator, int initialCapacity) {
+    super(initialCapacity);
+    setComparator(comparator);
+  }
+
+  /**
+   * Erzeugt einen neuen {@code SortableVector}
+   * @param comparator bestimmt die Sortierung
+   */
+  public SortableVector(Comparator comparator) {
+    super();
+    setComparator(comparator);
+  }
+
+  /**
+   * Erzeugt einen neuen {@code SortableVector}
+   * @param comparator bestimmt die Sortierung
+   */
+  public SortableVector(Comparator comparator, Collection c) {
+    super(c);
+    setComparator(comparator);
+  }
+
+  /**
+   * Belegt die globale Variable {@link #comparator} mit einem neuen Wert.
+   * Wird {@code null} uebergeben, wird der {@link DefaultComparator} verwendet
+   * @param comparator ein Comparator
+   */
+  private void setComparator(Comparator comparator) {
+    this.comparator = (comparator != null) ? comparator : DefaultComparator.DEFAULT;
+    this.invertedComparator = DefaultComparator.invert(this.comparator);
+  }
+
+  /**
+   * Sortiert den Vector.
+   */
+  public void sort() {
+    Arrays.sort( this.elementData, comparator );
+  }
+
+  /**
+   * Sortiert den Vector in der umgekehrten Reihenfolge.
+   */
+  public void sortInverted() {
+    Arrays.sort( this.elementData, invertedComparator );
+  }
+
+}

Modified: trunk/src/schmitzm/lang/StepThread.java
===================================================================
--- trunk/src/schmitzm/lang/StepThread.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/lang/StepThread.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,100 +1,118 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.lang;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+/**
+ * Diese Klasse stellt einen "arbeitenden" Thread dar (im Gegensatz zum
+ * "konkurrierenden" Thread, der mit anderen Threads auf gemeinsame Ressourcen
+ * zugreift). Die Arbeitsweise des <code>StepThread</code> erfolgt durch
+ * immer wiederkehrende Arbeitsschritte. Der Thread kann
+ * <ul>
+ * <li>gestartet werden ({@link #start()})</li>
+ * <li>angehalten werden ({@link #pause()})</li>
+ * <li>fortgesetzt werden ({@link #resume()})</li>
+ * <li>abgebrochen werden ({@link #terminate()})</li>
+ * <li>schrittweise ausgefuehrt werden (step)</li>
+ * </ul>
+ * @author Martin Schmitz
+ * @version 1.0
+ */
+public abstract class StepThread extends WorkingThread {
+  /** Modus "Thread fuehrt aktuellen Schritt zu Ende und wechselt dann in
+   *  'Pause'". */
+  public static final int MODE_STEP = 5;
 
-package schmitzm.lang;
-
-
-/**
- * Diese Klasse stellt einen "arbeitenden" Thread dar (im Gegensatz zum
- * "konkurrierenden" Thread, der mit anderen Threads auf gemeinsame Ressourcen
- * zugreift). Die Arbeitsweise des <code>StepThread</code> erfolgt durch
- * immer wiederkehrende Arbeitsschritte. Der Thread kann
- * <ul>
- * <li>gestartet werden ({@link #start()})</li>
- * <li>angehalten werden ({@link #pause()})</li>
- * <li>fortgesetzt werden ({@link #resume()})</li>
- * <li>abgebrochen werden ({@link #terminate()})</li>
- * <li>schrittweise ausgefuehrt werden (step)</li>
- * </ul>
- * @author Martin Schmitz
- * @version 1.0
- */
-public abstract class StepThread extends WorkingThread {
-  /** Modus "Thread fuehrt aktuellen Schritt zu Ende und wechselt dann in
-   *  'Pause'". */
-  public static final int MODE_STEP = 5;
-
-  /**
-   * Erzeugt einen neuen Prozess.
-   * @param name Name fuer den Thread
-   */
-  public StepThread(String name) {
-    super(name);
-  }
-
-  /**
-   * Erzeugt einen neuen Prozess.
-   */
-  public StepThread() {
-    super();
-  }
-
-  /**
-   * Fuehrt einen einzelnen Arbeitsschritt aus. Danach wird der Thread
-   * wieder schlafen gelegt.
-   */
-  public void step() {
-    boolean wasSleeping = isSleeping();
-
-    this.mode = MODE_STEP;
-    // beim allerersten Mal muss der Thread gestartet werden
-    if ( !isAlive() )
-      super.start();
-    else
-      if ( wasSleeping )
-        wakeUp();
-  }
-
-  /**
-   * Implementiert den konitinuierlichen Arbeitsablauf des Threads als eine
-   * Schleife, die fortlaufend {@link #performStep(int)} aufruft.
-   */
-  protected void performWork() {
-    for( int step=1;; step++ ) {
-       try {
-         checkBreakingCommands();
-       }
-       catch (ThreadDeath err) {
-         return;
-       }
-
-       switch (mode) {
-         case MODE_RUN:  performStep(step);
-                         // wurde waehrend der Ausfuehrung des
-                         // Schritts ein Step-Signal gegeben, wird nur
-                         // der aktuelle Schritt beendet und kein neuer
-                         // begonnen.
-                         if ( mode == MODE_STEP )
-                           mode = MODE_PAUSE;
-                         break;
-         case MODE_STEP: performStep(step);
-                         mode = MODE_PAUSE;
-                         break;
-       }
-     }
-
-  }
-
-  /**
-   * Implementiert einen Arbeitsschritt des Threads.
-   */
-  protected abstract void performStep(int stepNo);
-}
+  /**
+   * Erzeugt einen neuen Prozess.
+   * @param name Name fuer den Thread
+   */
+  public StepThread(String name) {
+    super(name);
+  }
+
+  /**
+   * Erzeugt einen neuen Prozess.
+   */
+  public StepThread() {
+    super();
+  }
+
+  /**
+   * Fuehrt einen einzelnen Arbeitsschritt aus. Danach wird der Thread
+   * wieder schlafen gelegt.
+   */
+  public void step() {
+    boolean wasSleeping = isSleeping();
+
+    this.mode = MODE_STEP;
+    // beim allerersten Mal muss der Thread gestartet werden
+    if ( !isAlive() )
+      super.start();
+    else
+      if ( wasSleeping )
+        wakeUp();
+  }
+
+  /**
+   * Implementiert den konitinuierlichen Arbeitsablauf des Threads als eine
+   * Schleife, die fortlaufend {@link #performStep(int)} aufruft.
+   */
+  protected void performWork() {
+    for( int step=1;; step++ ) {
+       try {
+         checkBreakingCommands();
+       }
+       catch (ThreadDeath err) {
+         return;
+       }
+
+       switch (mode) {
+         case MODE_RUN:  performStep(step);
+                         // wurde waehrend der Ausfuehrung des
+                         // Schritts ein Step-Signal gegeben, wird nur
+                         // der aktuelle Schritt beendet und kein neuer
+                         // begonnen.
+                         if ( mode == MODE_STEP )
+                           mode = MODE_PAUSE;
+                         break;
+         case MODE_STEP: performStep(step);
+                         mode = MODE_PAUSE;
+                         break;
+       }
+     }
+
+  }
+
+  /**
+   * Implementiert einen Arbeitsschritt des Threads.
+   */
+  protected abstract void performStep(int stepNo);
+}

Modified: trunk/src/schmitzm/lang/WorkingThread.java
===================================================================
--- trunk/src/schmitzm/lang/WorkingThread.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/lang/WorkingThread.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,303 +1,321 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.lang;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+import java.util.Vector;
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+/**
+ * Diese Klasse stellt einen "arbeitenden" Thread dar (im Gegensatz zum
+ * "konkurrierenden" Thread, der mit anderen Threads auf gemeinsame Ressourcen
+ * zugreift). Der <code>WorkingThread</code> kann
+ * <ul>
+ * <li>gestartet werden ({@link #start()})</li>
+ * <li>angehalten werden ({@link #pause()})</li>
+ * <li>fortgesetzt werden ({@link #resume()})</li>
+ * <li>abgebrochen werden ({@link #terminate()})</li>
+ * </ul>
+ * @author Martin Schmitz
+ * @version 1.0
+ */
+public abstract class WorkingThread extends Thread {
+  /** Modus "Thread ist bereit, gestartet zu werden". */
+  public static final int MODE_READY = 1;
+  /** Modus "Thread ist initialisiert, und laeuft". */
+  public static final int MODE_RUN = 2;
+  /** Modus "Thread ist beendet".<br>
+   *  <b>Der Thread kann nicht neu initialisiert oder gestartet werden!</b> */
+  public static final int MODE_TERMINATE = 3;
+  /** Modus "Thread pausiert und kann fortgesetzt werden". */
+  public static final int MODE_PAUSE = 4;
+//  /** Modus "Thread fuehrt aktuellen Schritt zu Ende und wechselt dann in
+//   *  'Pause'". */
+//  public static final int MODE_STEP = 5;
 
-package schmitzm.lang;
-
-import java.util.Vector;
-
-/**
- * Diese Klasse stellt einen "arbeitenden" Thread dar (im Gegensatz zum
- * "konkurrierenden" Thread, der mit anderen Threads auf gemeinsame Ressourcen
- * zugreift). Der <code>WorkingThread</code> kann
- * <ul>
- * <li>gestartet werden ({@link #start()})</li>
- * <li>angehalten werden ({@link #pause()})</li>
- * <li>fortgesetzt werden ({@link #resume()})</li>
- * <li>abgebrochen werden ({@link #terminate()})</li>
- * </ul>
- * @author Martin Schmitz
- * @version 1.0
- */
-public abstract class WorkingThread extends Thread {
-  /** Modus "Thread ist bereit, gestartet zu werden". */
-  public static final int MODE_READY = 1;
-  /** Modus "Thread ist initialisiert, und laeuft". */
-  public static final int MODE_RUN = 2;
-  /** Modus "Thread ist beendet".<br>
-   *  <b>Der Thread kann nicht neu initialisiert oder gestartet werden!</b> */
-  public static final int MODE_TERMINATE = 3;
-  /** Modus "Thread pausiert und kann fortgesetzt werden". */
-  public static final int MODE_PAUSE = 4;
-//  /** Modus "Thread fuehrt aktuellen Schritt zu Ende und wechselt dann in
-//   *  'Pause'". */
-//  public static final int MODE_STEP = 5;
-
-  /** Speichert den aktuellen Thread-Status. */
-  protected int mode = MODE_READY;
-  /** Speichert die Listener, die auf den Thread horchen. */
-  protected Vector listeners = new Vector<WorkingThreadListener>();
-
-  private String name = null;
-
-  /**
-   * Erzeugt einen neuen Thread.
-   * @param name Bezeichnung fuer den Thread
-   */
-  public WorkingThread(String name) {
-    this.name = name;
-  }
-
-  /**
-   * Erzeugt einen neuen Thread.
-   */
-  public WorkingThread() {
-    this(null);
-  }
-
-  /**
-   * Liefert den Status, in dem sich der Thread gerade befindet.
-   */
-  public int getMode() {
-    return mode;
-  }
-
-  /**
-   * Liefert den Namen des Threads. Falls dieser nicht gesetzt ist, wird
-   * <code>super.toString()</code> zurueckgegeben.
-   */
-  public String toString() {
-    return this.name != null ? this.name : super.toString();
-  }
-
-  /**
-   * Legt den Thread schlafen, bis er durch <code>wakeUp()</code>
-   * wieder aktiviert wird. Loest {@link WorkingThread#fireThreadPaused()} aus.
-   * @see #wakeUp()
-   */
-  protected synchronized void goSleep() {
-    try {
-      fireThreadPaused();
-      wait();
-    }
-    catch ( InterruptedException err ) {
-    }
-  }
-
-  /**
-   * Aktiviert den Thread wieder, nachdem er durch <code>goSleep()</code>
-   * Schlafen gelegt wurde. Loest {@link WorkingThread#fireThreadResumed()} aus.
-   * @see #goSleep()
-   */
-  protected synchronized void wakeUp() {
-    notify();
-    fireThreadResumed();
-  }
-
-  /**
-   * Startet den Thread (erneut). Beim allerersten Mal wird die
-   * <code>performInit()</code>-Methode aufgerufen.
-   * @see #performInit()
-   */
-  public void start() {
-    boolean wasSleeping = isSleeping();
-
-    this.mode = MODE_RUN;
-    // beim allerersten Mal muss der Thread gestartet werden
-    if ( !isAlive() ) {
-      performInit();
-      super.start();
-    } else {
-      if ( wasSleeping )
-        wakeUp();
-    }
-  }
-
-  /**
-   * Beendet (temporaer) die Arbeit des Threads. Ueber die
-   * <code>start()</code>- oder <code>step()</code>-Methode kann die Arbeit
-   * wieder aufgenommen werden.
-   */
-  public void pause() {
-    boolean wasSleeping = isSleeping();
-
-    this.mode = MODE_PAUSE;
-    // beim allerersten Mal muss der Thread gestartet werden
-    if ( !isAlive() )
-      super.start();
-    else
-      if ( wasSleeping )
-        wakeUp();
-    checkBreakingCommands();
-  }
-
-  /**
-   * Beendet den Thread, in dem die Run-Methode auslaeuft. Danach kann der
-   * Thread <b>nicht</b> mehr neu gestartet werden.
-   *
-   */
-  public void terminate() {
-    boolean wasSleeping = isSleeping();
-
-    this.mode = MODE_TERMINATE;
-    if ( !isAlive() && !isInterrupted() )
-      super.start();
-    else
-      if ( wasSleeping )
-        wakeUp();
-  }
-
-  /**
-   * Checkt, ob der Thread aktuell am arbeiten ist.
-   */
-  public boolean isRunning() {
-    return mode == MODE_RUN;
-  }
-
-  /**
-   * Checkt, ob der Thread aktuell am warten ist. Dies ist er, wenn er
-   * manuell in den Pause-Mode versetzt wurde.
-   * @see #pause()
-   */
-  public boolean isSleeping() {
-    return mode == MODE_PAUSE;
-  }
-
-  /**
-   * Implementiert den Arbeitsablauf des Threads.
-   * Sollte nicht manuell aufgerufen werden, da der aufrufende Prozess
-   * sonst blockiert. Loest zunaechst {@link WorkingThread#fireThreadStarted()}
-   * aus und {@link WorkingThread#fireThreadStopped()} bevor der Thread
-   * auslaeuft.
-   * @see #start()
-   * @see #performWork()
-   */
-  public void run() {
-    fireThreadStarted();
-    try {
-      // Thread wurde nur gestartet, um auszulaufen!
-      if (mode != MODE_TERMINATE)
-        performWork();
-    } catch (ThreadDeath err) {
-//      err.printStackTrace();
-    }
-    mode = MODE_TERMINATE;
-    performDispose();
-    fireThreadStopped();
-  }
-
-  /**
-   * Prueft, on ein Unterbrechnung-Signal erfolgt ist (<code>pause()</code>
-   * oder <code>terminate()</code>).<br>
-   * Bei <code>pause()</code> wird der Thread sofort schlafen gelegt. Bei
-   * <code>terminate()</code> wird eine <code>ThreadDeath</code>-Exception
-   * geworfen. Diese Methode kann/sollte an geeigneten Stellen im
-   * {@linkplain #performWork() Arbeitsablauf} aufgerufen werden.
-   */
-  protected void checkBreakingCommands() {
-    switch (mode) {
-      case MODE_TERMINATE: throw new ThreadDeath();
-      case MODE_PAUSE: goSleep();
-                       break;
-    }
-  }
-
-  /**
-   * Wird beim allerersten Aufruf der <code>start()</code>-Methode
-   * aufgerufen, um Thread-Komponenten zu initialisieren.
-   * <b>Sollte {@link #fireThreadInitialised()} aufrufen!</b>
-   */
-  protected abstract void performInit();
-
-  /**
-   * Implementiert den Arbeitsablauf des Threads.<br>
-   * Zwischendurch sollte an geeigneter Stelle immer wieder die
-   * {@link #checkBreakingCommands()}-Methode aufgerufen werden, um
-   * auf Pause- oder Terminate-Signale zu reagieren.
-   */
-  protected abstract void performWork();
-
-  /**
-   * Implementiert alle Aktionen, die nach Auslaufen des Threads
-   * durchzufuehren sind. z.B. sollte der Thread alle verteilten Listener
-   * von anderen Objekten wieder entfernen, damit er nicht mehr informiert
-   * wird. Diese Methode wird vor dem Auslaufen der {@link #run()}-Methode
-   * aufgerufen.
-   */
-  protected abstract void performDispose();
-
-  /**
-   * Fuegt einen Listener hinzu.
-   * @return <code>true</code> wenn dass Hinzufuegen erfolgreich war (siehe
-   *         {@link Vector#add(Object)})
-   */
-  public boolean addThreadListener(WorkingThreadListener listener) {
-    return listeners.add(listener);
-  }
-
-  /**
-   * Entfernt einen Listener von dem Thread.
-   * @return <code>true</code> wenn dass Entfernen erfolgreich war (siehe
-   *         {@link Vector#remove(Object)})
-   */
-  public boolean removeThreadListener(WorkingThreadListener listener) {
-    return listeners.remove(listener);
-  }
-
-  /**
-   * Informiert alle {@link WorkingThreadListener} darueber, dass der Thread
-   * initialisiert wurde.
-   */
-  protected void fireThreadInitialised() {
-//    System.err.println("Thread init");
-    for (int i=0; i<listeners.size(); i++)
-      ((WorkingThreadListener)listeners.get(i)).threadInitialised(this);
-  }
-
-  /**
-   * Informiert alle {@link WorkingThreadListener} darueber, dass der Thread
-   * gestartet wurde.
-   */
-  protected void fireThreadStarted() {
-//    System.err.println("Thread started");
-    for (int i=0; i<listeners.size(); i++)
-      ((WorkingThreadListener)listeners.get(i)).threadStarted(this);
-  }
-
-  /**
-   * Informiert alle {@link WorkingThreadListener} darueber, dass der Thread
-   * pausiert.
-   */
-  protected void fireThreadPaused() {
-//    System.err.println("Thread paused");
-    for (int i=0; i<listeners.size(); i++)
-      ((WorkingThreadListener)listeners.get(i)).threadPaused(this);
-  }
-
-  /**
-   * Informiert alle {@link WorkingThreadListener} darueber, dass der Thread
-   * (nach einer Pause) wieder arbeitet.
-   */
-  protected void fireThreadResumed() {
-//    System.err.println("Thread resumed");
-    for (int i=0; i<listeners.size(); i++)
-      ((WorkingThreadListener)listeners.get(i)).threadResumed(this);
-  }
-
-  /**
-   * Informiert alle {@link WorkingThreadListener} darueber, dass der Thread
-   * gestoppt wurde oder ausgelaufen ist.
-   */
-  protected void fireThreadStopped() {
-//    System.err.println("Thread stopped");
-   for (int i=0; i<listeners.size(); i++)
-      ((WorkingThreadListener)listeners.get(i)).threadStopped(this);
-  }
-}
+  /** Speichert den aktuellen Thread-Status. */
+  protected int mode = MODE_READY;
+  /** Speichert die Listener, die auf den Thread horchen. */
+  protected Vector listeners = new Vector<WorkingThreadListener>();
+
+  private String name = null;
+
+  /**
+   * Erzeugt einen neuen Thread.
+   * @param name Bezeichnung fuer den Thread
+   */
+  public WorkingThread(String name) {
+    this.name = name;
+  }
+
+  /**
+   * Erzeugt einen neuen Thread.
+   */
+  public WorkingThread() {
+    this(null);
+  }
+
+  /**
+   * Liefert den Status, in dem sich der Thread gerade befindet.
+   */
+  public int getMode() {
+    return mode;
+  }
+
+  /**
+   * Liefert den Namen des Threads. Falls dieser nicht gesetzt ist, wird
+   * <code>super.toString()</code> zurueckgegeben.
+   */
+  public String toString() {
+    return this.name != null ? this.name : super.toString();
+  }
+
+  /**
+   * Legt den Thread schlafen, bis er durch <code>wakeUp()</code>
+   * wieder aktiviert wird. Loest {@link WorkingThread#fireThreadPaused()} aus.
+   * @see #wakeUp()
+   */
+  protected synchronized void goSleep() {
+    try {
+      fireThreadPaused();
+      wait();
+    }
+    catch ( InterruptedException err ) {
+    }
+  }
+
+  /**
+   * Aktiviert den Thread wieder, nachdem er durch <code>goSleep()</code>
+   * Schlafen gelegt wurde. Loest {@link WorkingThread#fireThreadResumed()} aus.
+   * @see #goSleep()
+   */
+  protected synchronized void wakeUp() {
+    notify();
+    fireThreadResumed();
+  }
+
+  /**
+   * Startet den Thread (erneut). Beim allerersten Mal wird die
+   * <code>performInit()</code>-Methode aufgerufen.
+   * @see #performInit()
+   */
+  public void start() {
+    boolean wasSleeping = isSleeping();
+
+    this.mode = MODE_RUN;
+    // beim allerersten Mal muss der Thread gestartet werden
+    if ( !isAlive() ) {
+      performInit();
+      super.start();
+    } else {
+      if ( wasSleeping )
+        wakeUp();
+    }
+  }
+
+  /**
+   * Beendet (temporaer) die Arbeit des Threads. Ueber die
+   * <code>start()</code>- oder <code>step()</code>-Methode kann die Arbeit
+   * wieder aufgenommen werden.
+   */
+  public void pause() {
+    boolean wasSleeping = isSleeping();
+
+    this.mode = MODE_PAUSE;
+    // beim allerersten Mal muss der Thread gestartet werden
+    if ( !isAlive() )
+      super.start();
+    else
+      if ( wasSleeping )
+        wakeUp();
+    checkBreakingCommands();
+  }
+
+  /**
+   * Beendet den Thread, in dem die Run-Methode auslaeuft. Danach kann der
+   * Thread <b>nicht</b> mehr neu gestartet werden.
+   *
+   */
+  public void terminate() {
+    boolean wasSleeping = isSleeping();
+
+    this.mode = MODE_TERMINATE;
+    if ( !isAlive() && !isInterrupted() )
+      super.start();
+    else
+      if ( wasSleeping )
+        wakeUp();
+  }
+
+  /**
+   * Checkt, ob der Thread aktuell am arbeiten ist.
+   */
+  public boolean isRunning() {
+    return mode == MODE_RUN;
+  }
+
+  /**
+   * Checkt, ob der Thread aktuell am warten ist. Dies ist er, wenn er
+   * manuell in den Pause-Mode versetzt wurde.
+   * @see #pause()
+   */
+  public boolean isSleeping() {
+    return mode == MODE_PAUSE;
+  }
+
+  /**
+   * Implementiert den Arbeitsablauf des Threads.
+   * Sollte nicht manuell aufgerufen werden, da der aufrufende Prozess
+   * sonst blockiert. Loest zunaechst {@link WorkingThread#fireThreadStarted()}
+   * aus und {@link WorkingThread#fireThreadStopped()} bevor der Thread
+   * auslaeuft.
+   * @see #start()
+   * @see #performWork()
+   */
+  public void run() {
+    fireThreadStarted();
+    try {
+      // Thread wurde nur gestartet, um auszulaufen!
+      if (mode != MODE_TERMINATE)
+        performWork();
+    } catch (ThreadDeath err) {
+//      err.printStackTrace();
+    }
+    mode = MODE_TERMINATE;
+    performDispose();
+    fireThreadStopped();
+  }
+
+  /**
+   * Prueft, on ein Unterbrechnung-Signal erfolgt ist (<code>pause()</code>
+   * oder <code>terminate()</code>).<br>
+   * Bei <code>pause()</code> wird der Thread sofort schlafen gelegt. Bei
+   * <code>terminate()</code> wird eine <code>ThreadDeath</code>-Exception
+   * geworfen. Diese Methode kann/sollte an geeigneten Stellen im
+   * {@linkplain #performWork() Arbeitsablauf} aufgerufen werden.
+   */
+  protected void checkBreakingCommands() {
+    switch (mode) {
+      case MODE_TERMINATE: throw new ThreadDeath();
+      case MODE_PAUSE: goSleep();
+                       break;
+    }
+  }
+
+  /**
+   * Wird beim allerersten Aufruf der <code>start()</code>-Methode
+   * aufgerufen, um Thread-Komponenten zu initialisieren.
+   * <b>Sollte {@link #fireThreadInitialised()} aufrufen!</b>
+   */
+  protected abstract void performInit();
+
+  /**
+   * Implementiert den Arbeitsablauf des Threads.<br>
+   * Zwischendurch sollte an geeigneter Stelle immer wieder die
+   * {@link #checkBreakingCommands()}-Methode aufgerufen werden, um
+   * auf Pause- oder Terminate-Signale zu reagieren.
+   */
+  protected abstract void performWork();
+
+  /**
+   * Implementiert alle Aktionen, die nach Auslaufen des Threads
+   * durchzufuehren sind. z.B. sollte der Thread alle verteilten Listener
+   * von anderen Objekten wieder entfernen, damit er nicht mehr informiert
+   * wird. Diese Methode wird vor dem Auslaufen der {@link #run()}-Methode
+   * aufgerufen.
+   */
+  protected abstract void performDispose();
+
+  /**
+   * Fuegt einen Listener hinzu.
+   * @return <code>true</code> wenn dass Hinzufuegen erfolgreich war (siehe
+   *         {@link Vector#add(Object)})
+   */
+  public boolean addThreadListener(WorkingThreadListener listener) {
+    return listeners.add(listener);
+  }
+
+  /**
+   * Entfernt einen Listener von dem Thread.
+   * @return <code>true</code> wenn dass Entfernen erfolgreich war (siehe
+   *         {@link Vector#remove(Object)})
+   */
+  public boolean removeThreadListener(WorkingThreadListener listener) {
+    return listeners.remove(listener);
+  }
+
+  /**
+   * Informiert alle {@link WorkingThreadListener} darueber, dass der Thread
+   * initialisiert wurde.
+   */
+  protected void fireThreadInitialised() {
+//    System.err.println("Thread init");
+    for (int i=0; i<listeners.size(); i++)
+      ((WorkingThreadListener)listeners.get(i)).threadInitialised(this);
+  }
+
+  /**
+   * Informiert alle {@link WorkingThreadListener} darueber, dass der Thread
+   * gestartet wurde.
+   */
+  protected void fireThreadStarted() {
+//    System.err.println("Thread started");
+    for (int i=0; i<listeners.size(); i++)
+      ((WorkingThreadListener)listeners.get(i)).threadStarted(this);
+  }
+
+  /**
+   * Informiert alle {@link WorkingThreadListener} darueber, dass der Thread
+   * pausiert.
+   */
+  protected void fireThreadPaused() {
+//    System.err.println("Thread paused");
+    for (int i=0; i<listeners.size(); i++)
+      ((WorkingThreadListener)listeners.get(i)).threadPaused(this);
+  }
+
+  /**
+   * Informiert alle {@link WorkingThreadListener} darueber, dass der Thread
+   * (nach einer Pause) wieder arbeitet.
+   */
+  protected void fireThreadResumed() {
+//    System.err.println("Thread resumed");
+    for (int i=0; i<listeners.size(); i++)
+      ((WorkingThreadListener)listeners.get(i)).threadResumed(this);
+  }
+
+  /**
+   * Informiert alle {@link WorkingThreadListener} darueber, dass der Thread
+   * gestoppt wurde oder ausgelaufen ist.
+   */
+  protected void fireThreadStopped() {
+//    System.err.println("Thread stopped");
+   for (int i=0; i<listeners.size(); i++)
+      ((WorkingThreadListener)listeners.get(i)).threadStopped(this);
+  }
+}

Modified: trunk/src/schmitzm/lang/WorkingThreadAdapter.java
===================================================================
--- trunk/src/schmitzm/lang/WorkingThreadAdapter.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/lang/WorkingThreadAdapter.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,58 +1,76 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.lang;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+/**
+ * Diese Klasse stellt eine Basis-Implementierung des Interfaces
+ * {@link WorkingThreadListener} dar. <b>Die implementierten Methoden machen
+ * jedoch allesamt nichts.</b> Die Klasse dient lediglich der Vereinfachung,
+ * dass nicht benoetigte Methoden auch nicht implementiert werden muessen.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class WorkingThreadAdapter implements WorkingThreadListener {
+  /**
+   * Wird ausgeloest, nachdem der Thread initialisiert wurde.
+   * @param thread ausloesender Thread
+   */
+  public void threadInitialised(WorkingThread thread) {
+  }
 
-package schmitzm.lang;
-
-
-/**
- * Diese Klasse stellt eine Basis-Implementierung des Interfaces
- * {@link WorkingThreadListener} dar. <b>Die implementierten Methoden machen
- * jedoch allesamt nichts.</b> Die Klasse dient lediglich der Vereinfachung,
- * dass nicht benoetigte Methoden auch nicht implementiert werden muessen.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class WorkingThreadAdapter implements WorkingThreadListener {
-  /**
-   * Wird ausgeloest, nachdem der Thread initialisiert wurde.
-   * @param thread ausloesender Thread
-   */
-  public void threadInitialised(WorkingThread thread) {
-  }
-
-  /**
-   * Wird ausgeloest, nachdem der Thread (temporaer) angehalten wurde.
-   * @param thread ausloesender Thread
-   */
-  public void threadPaused(WorkingThread thread) {
-  }
-
-  /**
-   * Wird ausgeloest, nachdem der Thread fortgesetzt wurde.
-   * @param thread ausloesender Thread
-   */
-  public void threadResumed(WorkingThread thread) {
-  }
-
-  /**
-   * Wird ausgeloest, nachdem der Thread gestartet wurde.
-   * @param thread ausloesender Thread
-   */
-  public void threadStarted(WorkingThread thread) {
-  }
-
-  /**
-   * Wird ausgeloest, nachdem der Thread komplett gestoppt hat.
-   * @param thread ausloesender Thread
-   */
-  public void threadStopped(WorkingThread thread) {
-  }
-}
+  /**
+   * Wird ausgeloest, nachdem der Thread (temporaer) angehalten wurde.
+   * @param thread ausloesender Thread
+   */
+  public void threadPaused(WorkingThread thread) {
+  }
+
+  /**
+   * Wird ausgeloest, nachdem der Thread fortgesetzt wurde.
+   * @param thread ausloesender Thread
+   */
+  public void threadResumed(WorkingThread thread) {
+  }
+
+  /**
+   * Wird ausgeloest, nachdem der Thread gestartet wurde.
+   * @param thread ausloesender Thread
+   */
+  public void threadStarted(WorkingThread thread) {
+  }
+
+  /**
+   * Wird ausgeloest, nachdem der Thread komplett gestoppt hat.
+   * @param thread ausloesender Thread
+   */
+  public void threadStopped(WorkingThread thread) {
+  }
+}

Modified: trunk/src/schmitzm/lang/WorkingThreadListener.java
===================================================================
--- trunk/src/schmitzm/lang/WorkingThreadListener.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/lang/WorkingThreadListener.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,52 +1,70 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.lang;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+/**
+ * Diese Klasse stellt einen Listener dar, der bei bestimmten Thread-Aktivitaeten
+ * informiert wird.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public interface WorkingThreadListener {
+  /**
+   * Wird ausgeloest, nachdem der Thread initialisiert wurde.
+   * @param thread ausloesender Thread
+   */
+  public void threadInitialised(WorkingThread thread);
 
-package schmitzm.lang;
-
-
-/**
- * Diese Klasse stellt einen Listener dar, der bei bestimmten Thread-Aktivitaeten
- * informiert wird.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public interface WorkingThreadListener {
-  /**
-   * Wird ausgeloest, nachdem der Thread initialisiert wurde.
-   * @param thread ausloesender Thread
-   */
-  public void threadInitialised(WorkingThread thread);
-
-  /**
-   * Wird ausgeloest, nachdem der Thread komplett gestoppt hat.
-   * @param thread ausloesender Thread
-   */
-  public void threadStopped(WorkingThread thread);
-
-  /**
-   * Wird ausgeloest, nachdem der Thread gestartet wurde.
-   * @param thread ausloesender Thread
-   */
-  public void threadStarted(WorkingThread thread);
-
-  /**
-   * Wird ausgeloest, nachdem der Thread (temporaer) angehalten wurde.
-   * @param thread ausloesender Thread
-   */
-  public void threadPaused(WorkingThread thread);
-
-  /**
-   * Wird ausgeloest, nachdem der Thread fortgesetzt wurde.
-   * @param thread ausloesender Thread
-   */
-  public void threadResumed(WorkingThread thread);
-
-}
+  /**
+   * Wird ausgeloest, nachdem der Thread komplett gestoppt hat.
+   * @param thread ausloesender Thread
+   */
+  public void threadStopped(WorkingThread thread);
+
+  /**
+   * Wird ausgeloest, nachdem der Thread gestartet wurde.
+   * @param thread ausloesender Thread
+   */
+  public void threadStarted(WorkingThread thread);
+
+  /**
+   * Wird ausgeloest, nachdem der Thread (temporaer) angehalten wurde.
+   * @param thread ausloesender Thread
+   */
+  public void threadPaused(WorkingThread thread);
+
+  /**
+   * Wird ausgeloest, nachdem der Thread fortgesetzt wurde.
+   * @param thread ausloesender Thread
+   */
+  public void threadResumed(WorkingThread thread);
+
+}

Modified: trunk/src/schmitzm/lang/resource/locales/LangResourceBundle.properties
===================================================================
--- trunk/src/schmitzm/lang/resource/locales/LangResourceBundle.properties	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/lang/resource/locales/LangResourceBundle.properties	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,26 +1,55 @@
-# -----------------------------------------------------------
-# ------ Default Translations (english) for components ------
-# ------ in Package schmitzm.lang                      ------
-# -----------------------------------------------------------
-
-# --- Translations for OperationTree / OperationTreeParser
-OperationTree.Integer=Integer
-OperationTree.Number=Number
-OperationTree.err.ParseErrorMess=Parse-Error at "${0}": ${1}
-OperationTree.err.UnexpectedEOR=Unexpected end of rule!
-OperationTree.err.UnexpectedError=Unexpected error!
-OperationTree.err.TokenNotExpected=${0} not expected
-OperationTree.err.MoreParamsExpected=${0} more function parameters expected. Bracket can not close!
-OperationTree.err.UnexpectedBracket=Bracket ${0} can not close ${1}
-OperationTree.err.BracketsNotClosed=Bracket(s) not closed: ${0}
-OperationTree.err.IllegalOperator=Illegal operator ${0}
-OperationTree.err.IllegalOperatorSyntax=Illegal ${0} syntax '${1}'
-OperationTree.err.ParamSepExpected=Parameter-Separator expected
-OperationTree.err.IllegalCharacter=Illegal character '${0}' (${1} expected)");
-
-OperationTree.err.UnknownNode=Unknown operation tree node: ${0}
-OperationTree.err.UnknownOperator=Unknown operator: ${0}
-OperationTree.err.UnknownAliasOperator=Unknown alias operator: ${0}
-OperationTree.err.LessParams1=At least ${0} function parameters expected: ${1}(..)
-OperationTree.err.LessParams2=${0} function parameters expected: ${1}(..)
-OperationTree.err.IllegalParam=Illegal parameter ${0} for ${1}(..): ${2} expected
+##########
+#Copyright (c) 2009 Martin O. J. Schmitz.
+#
+#This file is part of the SCHMITZM library - a collection of utility 
+#classes based on Java 1.6, focussing (not only) on Java Swing 
+#and the Geotools library.
+#
+#The SCHMITZM project is hosted at:
+#http://wald.intevation.org/projects/schmitzm/
+#
+#This program is free software; you can redistribute it and/or
+#modify it under the terms of the GNU Lesser General Public License
+#as published by the Free Software Foundation; either version 3
+#of the License, or (at your option) any later version.
+#
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+#
+#You should have received a copy of the GNU Lesser General Public License (license.txt)
+#along with this program; if not, write to the Free Software
+#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#or try this link: http://www.gnu.org/licenses/lgpl.html
+#
+#Contributors:
+#    Martin O. J. Schmitz - initial API and implementation
+#    Stefan A. Krüger - additional utility classes
+##########
+# -----------------------------------------------------------
+# ------ Default Translations (english) for components ------
+# ------ in Package schmitzm.lang                      ------
+# -----------------------------------------------------------
+
+# --- Translations for OperationTree / OperationTreeParser
+OperationTree.Integer=Integer
+OperationTree.Number=Number
+OperationTree.err.ParseErrorMess=Parse-Error at "${0}": ${1}
+OperationTree.err.UnexpectedEOR=Unexpected end of rule!
+OperationTree.err.UnexpectedError=Unexpected error!
+OperationTree.err.TokenNotExpected=${0} not expected
+OperationTree.err.MoreParamsExpected=${0} more function parameters expected. Bracket can not close!
+OperationTree.err.UnexpectedBracket=Bracket ${0} can not close ${1}
+OperationTree.err.BracketsNotClosed=Bracket(s) not closed: ${0}
+OperationTree.err.IllegalOperator=Illegal operator ${0}
+OperationTree.err.IllegalOperatorSyntax=Illegal ${0} syntax '${1}'
+OperationTree.err.ParamSepExpected=Parameter-Separator expected
+OperationTree.err.IllegalCharacter=Illegal character '${0}' (${1} expected)");
+
+OperationTree.err.UnknownNode=Unknown operation tree node: ${0}
+OperationTree.err.UnknownOperator=Unknown operator: ${0}
+OperationTree.err.UnknownAliasOperator=Unknown alias operator: ${0}
+OperationTree.err.LessParams1=At least ${0} function parameters expected: ${1}(..)
+OperationTree.err.LessParams2=${0} function parameters expected: ${1}(..)
+OperationTree.err.IllegalParam=Illegal parameter ${0} for ${1}(..): ${2} expected

Modified: trunk/src/schmitzm/lang/resource/locales/LangResourceBundle_de.properties
===================================================================
--- trunk/src/schmitzm/lang/resource/locales/LangResourceBundle_de.properties	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/lang/resource/locales/LangResourceBundle_de.properties	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,26 +1,55 @@
-# ------------------------------------------------
-# ------ German Translations for components ------
-# ------ in Package schmitzm.lang           ------
-# ------------------------------------------------
-
-# --- Translations for OperationTree / OperationTreeParser
-OperationTree.Integer=Ganzzahl
-OperationTree.Number=Numerisch
-OperationTree.err.ParseErrorMess=Parser-Fehler bei "${0}": ${1}
-OperationTree.err.UnexpectedEOR=Unerwartetes Ende der Formel!
-OperationTree.err.UnexpectedError=Unerwarteter Fehler!
-OperationTree.err.TokenNotExpected=${0} nicht erlaubt
-OperationTree.err.MoreParamsExpected=Noch ${0} Funtionsparameter notwendig. Klammer kann nicht schliessen!
-OperationTree.err.UnexpectedBracket=Klammer ${0} kann ${1} nicht schliessen
-OperationTree.err.BracketsNotClosed=Klammer(n) werden nicht geschlossen: ${0}
-OperationTree.err.IllegalOperator=Ungültiger Operator ${0}
-OperationTree.err.IllegalOperatorSyntax=Fehlerhafte ${0} Syntax '${1}'
-OperationTree.err.ParamSepExpected=Parameter-Trennzeichen erwartet
-OperationTree.err.IllegalCharacter=Ungültiges Zeichen '${0}' (${1} erwartet)");
-
-OperationTree.err.UnknownNode=Unbekannter Operator-Knoten: ${0}
-OperationTree.err.UnknownOperator=Unbekannter Operator: ${0}
-OperationTree.err.UnknownAliasOperator=Unbekannter Alias-Operator: ${0}
-OperationTree.err.LessParams1=Mindestens ${0} Funktionsparameter benötigt: ${1}(..)
-OperationTree.err.LessParams2=${0} Funktionsparameter benötigt: ${1}(..)
-OperationTree.err.IllegalParam=Illegaler Funktionsparameter ${0} für ${1}(..): ${2} erwartet
+##########
+#Copyright (c) 2009 Martin O. J. Schmitz.
+#
+#This file is part of the SCHMITZM library - a collection of utility 
+#classes based on Java 1.6, focussing (not only) on Java Swing 
+#and the Geotools library.
+#
+#The SCHMITZM project is hosted at:
+#http://wald.intevation.org/projects/schmitzm/
+#
+#This program is free software; you can redistribute it and/or
+#modify it under the terms of the GNU Lesser General Public License
+#as published by the Free Software Foundation; either version 3
+#of the License, or (at your option) any later version.
+#
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+#
+#You should have received a copy of the GNU Lesser General Public License (license.txt)
+#along with this program; if not, write to the Free Software
+#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#or try this link: http://www.gnu.org/licenses/lgpl.html
+#
+#Contributors:
+#    Martin O. J. Schmitz - initial API and implementation
+#    Stefan A. Krüger - additional utility classes
+##########
+# ------------------------------------------------
+# ------ German Translations for components ------
+# ------ in Package schmitzm.lang           ------
+# ------------------------------------------------
+
+# --- Translations for OperationTree / OperationTreeParser
+OperationTree.Integer=Ganzzahl
+OperationTree.Number=Numerisch
+OperationTree.err.ParseErrorMess=Parser-Fehler bei "${0}": ${1}
+OperationTree.err.UnexpectedEOR=Unerwartetes Ende der Formel!
+OperationTree.err.UnexpectedError=Unerwarteter Fehler!
+OperationTree.err.TokenNotExpected=${0} nicht erlaubt
+OperationTree.err.MoreParamsExpected=Noch ${0} Funtionsparameter notwendig. Klammer kann nicht schliessen!
+OperationTree.err.UnexpectedBracket=Klammer ${0} kann ${1} nicht schliessen
+OperationTree.err.BracketsNotClosed=Klammer(n) werden nicht geschlossen: ${0}
+OperationTree.err.IllegalOperator=Ungültiger Operator ${0}
+OperationTree.err.IllegalOperatorSyntax=Fehlerhafte ${0} Syntax '${1}'
+OperationTree.err.ParamSepExpected=Parameter-Trennzeichen erwartet
+OperationTree.err.IllegalCharacter=Ungültiges Zeichen '${0}' (${1} erwartet)");
+
+OperationTree.err.UnknownNode=Unbekannter Operator-Knoten: ${0}
+OperationTree.err.UnknownOperator=Unbekannter Operator: ${0}
+OperationTree.err.UnknownAliasOperator=Unbekannter Alias-Operator: ${0}
+OperationTree.err.LessParams1=Mindestens ${0} Funktionsparameter benötigt: ${1}(..)
+OperationTree.err.LessParams2=${0} Funktionsparameter benötigt: ${1}(..)
+OperationTree.err.IllegalParam=Illegaler Funktionsparameter ${0} für ${1}(..): ${2} erwartet

Modified: trunk/src/schmitzm/lang/tree/BinaryTreeNode.java
===================================================================
--- trunk/src/schmitzm/lang/tree/BinaryTreeNode.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/lang/tree/BinaryTreeNode.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,236 +1,254 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.lang.tree;
-
-import java.util.Vector;
-
-/**
- * Diese Klasse stellt einen Knoten in einem Baum dar, der maximal 2 Kindknoten
- * hat, einen linken und einen rechten.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class BinaryTreeNode<E> extends TreeNode<E> {
-  /** Speichert das linke Kind des Knoten. */
-  protected BinaryTreeNode<E> leftChild = null;
-  /** Speichert das rechte Kind des Knoten. */
-  protected BinaryTreeNode<E> rightChild = null;
-
-  /**
-   * Erzeugt einen Wurzel-Knoten ohne Nachfolger.
-   */
-  public BinaryTreeNode() {
-    this((E)null);
-  }
-
-  /**
-   * Erzeugt einen Wurzel-Knoten ohne Nachfolger.
-   * @param object Objekt, das in dem Knoten gespeichert wird
-   */
-  public BinaryTreeNode(E object) {
-    this(object, null);
-  }
-
-  /**
-   * Erzeugt einen Blatt-Knoten.
-   * @param parent direkter Vorgaenger-Knoten
-   */
-  public BinaryTreeNode(BinaryTreeNode<E> parent) {
-    this(null, parent);
-  }
-
-  /**
-   * Erzeugt einen Blatt-Knoten.
-   * @param object Objekt, das in dem Knoten gespeichert wird
-   * @param parent direkter Vorgaenger-Knoten
-   */
-  public BinaryTreeNode(E object, BinaryTreeNode<E> parent) {
-    this(object,parent,null,null);
-  }
-
-  /**
-   * Erzeugt einen inneren Knoten.
-   * @param object Objekt, das in dem Knoten gespeichert wird
-   * @param parent direkter Vorgaenger-Knoten
-   */
-  public BinaryTreeNode(E object, BinaryTreeNode<E> parent, BinaryTreeNode<E> leftChild, BinaryTreeNode<E> rightChild) {
-    super(object,parent);
-    setLeftChild( leftChild );
-    setRightChild( rightChild );
-  }
-
-
-  /**
-   * Liefert den Wurzel-Knoten.
-   */
-  public BinaryTreeNode<E> getRoot() {
-    return (BinaryTreeNode)super.getRoot();
-  }
-
-  /**
-   * Liefert den direkten Vorgaenger-Knoten.
-   */
-  public BinaryTreeNode<E> getParent() {
-    return (BinaryTreeNode)super.getParent();
-  }
-
-  /**
-   * Prueft, ob es sich um einen Blattknoten handelt.
-   * @return <code>true<code> gdw. beide Kinder {@code null} sind
-   */
-  public boolean isLeaf() {
-    // Effizienter als die allgemeine super-Methode
-    return leftChild == null & rightChild == null;
-  }
-
-  /**
-   * Prueft, ob ein Knoten als Vater- oder Kind-Knoten fuer diesen Knoten
-   * verwendet werden kann
-   * @param node zu pruefende Knoten
-   * @exception IllegalArgumentException falls der Knoten nicht geeignet ist
-   */
-  public void checkNode(TreeNode<E> node) {
-    if ( node!=null && !(node instanceof BinaryTreeNode) )
-      throw new IllegalArgumentException("Node must be an BinaryTreeNode!");
-  }
-
-  /**
-   * Liefert die (maximale) Anzahl der Kindknoten.
-   * @return immer 2, unabhaengig davon, ob diese {@code null} sind oder nicht
-   */
-  public int getChildCount() {
-//    int count = 0;
-//    if ( leftChild != null )
-//      count++;
-//    if ( rightChild != null )
-//      count++;
-//    return count;
-      return 2;
-  }
-
-  /**
-   * Liefert einen Kindknoten.
-   * @param i Index (beginnend bei 0)
-   * @return den linken Knoten fuer i = 1, den rechten Knoten sonst
-   */
-  public BinaryTreeNode<E> getChild(int i) {
-    return ( i == 0 ) ? leftChild : rightChild;
-  }
-
-  /**
-   * Setzt einen Kindknoten. Setzt den linken Kind-Knoten fuer i = 1, den rechten
-   * Kind-Knoten sonst
-   * @param i Index (beginnend bei 0)
-   * @exception IllegalArgumentException falls {@code child} kein
-   *            {@code BinaryTreeNode<E>} ist
-   */
-  public void setChild(int i, TreeNode<E> child) {
-    checkNode(child);
-    TreeNode oldChild = null;
-    if ( i == 0 ) {
-      oldChild  = leftChild;
-      leftChild = (BinaryTreeNode<E>)child;
-    } else {
-      oldChild   = rightChild;
-      rightChild = (BinaryTreeNode<E>)child;
-    }
-    // Vater des alten Kind-Konten loeschen
-    if ( oldChild != null )
-      oldChild.setParent(null);
-    // Vater des neuen Kind-Konten setzen
-    if ( child != null )
-      child.setParent(this);
-  }
-
-  /**
-   * Liefert den linken Kindknoten.
-   */
-  public BinaryTreeNode<E> getLeftChild() {
-    return leftChild;
-  }
-
-  /**
-   * Setzt den linken Kindknoten.
-   */
-  public void setLeftChild(BinaryTreeNode<E> child) {
-    setChild(0,child);
-  }
-
-  /**
-   * Liefert den rechten Kindknoten.
-   */
-  public BinaryTreeNode<E> getRightChild() {
-    return rightChild;
-  }
-
-  /**
-   * Setzt den rechten Kindknoten.
-   */
-  public void setRightChild(BinaryTreeNode<E> child) {
-    setChild(1,child);
-  }
-
-  /**
-   * Liefert die im (Teil-)Baum des Knotens gespeicherten Objekte in der
-   * Inorder-Reihenfolge.
-   * @param v Liste in die die Objekte eingefuegt werden (kann {@code null} sein!)
-   */
-  public Vector<E> getObjectsInorder(Vector<E> v) {
-    if ( v == null )
-      v = new Vector<E>();
-
-    if ( leftChild != null )
-      leftChild.getObjectsInorder(v);
-    v.add(this.getObject());
-    if ( rightChild != null )
-      rightChild.getObjectsInorder(v);
-
-    return v;
-  }
-
-  /**
-   * Liefert die im (Teil-)Baum des Knotens gespeicherten Objekte in der
-   * Preorder-Reihenfolge.
-   * @param v Liste in die die Objekte eingefuegt werden (kann {@code null} sein!)
-   */
-  public Vector<E> getObjectsPreorder(Vector<E> v) {
-    if ( v == null )
-      v = new Vector<E>();
-
-    v.add(this.getObject());
-    if ( leftChild != null )
-      leftChild.getObjectsPreorder(v);
-    if ( rightChild != null )
-      rightChild.getObjectsPreorder(v);
-
-    return v;
-  }
-
-  /**
-   * Liefert die im (Teil-)Baum des Knotens gespeicherten Objekte in der
-   * Postorder-Reihenfolge.
-   * @param v Liste in die die Objekte eingefuegt werden (kann {@code null} sein!)
-   */
-  public Vector<E> getObjectsPostorder(Vector<E> v) {
-    if ( v == null )
-      v = new Vector<E>();
-
-    if ( leftChild != null )
-      leftChild.getObjectsPostorder(v);
-    if ( rightChild != null )
-      rightChild.getObjectsPostorder(v);
-    v.add(this.getObject());
-
-    return v;
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.lang.tree;
+
+import java.util.Vector;
+
+/**
+ * Diese Klasse stellt einen Knoten in einem Baum dar, der maximal 2 Kindknoten
+ * hat, einen linken und einen rechten.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class BinaryTreeNode<E> extends TreeNode<E> {
+  /** Speichert das linke Kind des Knoten. */
+  protected BinaryTreeNode<E> leftChild = null;
+  /** Speichert das rechte Kind des Knoten. */
+  protected BinaryTreeNode<E> rightChild = null;
+
+  /**
+   * Erzeugt einen Wurzel-Knoten ohne Nachfolger.
+   */
+  public BinaryTreeNode() {
+    this((E)null);
+  }
+
+  /**
+   * Erzeugt einen Wurzel-Knoten ohne Nachfolger.
+   * @param object Objekt, das in dem Knoten gespeichert wird
+   */
+  public BinaryTreeNode(E object) {
+    this(object, null);
+  }
+
+  /**
+   * Erzeugt einen Blatt-Knoten.
+   * @param parent direkter Vorgaenger-Knoten
+   */
+  public BinaryTreeNode(BinaryTreeNode<E> parent) {
+    this(null, parent);
+  }
+
+  /**
+   * Erzeugt einen Blatt-Knoten.
+   * @param object Objekt, das in dem Knoten gespeichert wird
+   * @param parent direkter Vorgaenger-Knoten
+   */
+  public BinaryTreeNode(E object, BinaryTreeNode<E> parent) {
+    this(object,parent,null,null);
+  }
+
+  /**
+   * Erzeugt einen inneren Knoten.
+   * @param object Objekt, das in dem Knoten gespeichert wird
+   * @param parent direkter Vorgaenger-Knoten
+   */
+  public BinaryTreeNode(E object, BinaryTreeNode<E> parent, BinaryTreeNode<E> leftChild, BinaryTreeNode<E> rightChild) {
+    super(object,parent);
+    setLeftChild( leftChild );
+    setRightChild( rightChild );
+  }
+
+
+  /**
+   * Liefert den Wurzel-Knoten.
+   */
+  public BinaryTreeNode<E> getRoot() {
+    return (BinaryTreeNode)super.getRoot();
+  }
+
+  /**
+   * Liefert den direkten Vorgaenger-Knoten.
+   */
+  public BinaryTreeNode<E> getParent() {
+    return (BinaryTreeNode)super.getParent();
+  }
+
+  /**
+   * Prueft, ob es sich um einen Blattknoten handelt.
+   * @return <code>true<code> gdw. beide Kinder {@code null} sind
+   */
+  public boolean isLeaf() {
+    // Effizienter als die allgemeine super-Methode
+    return leftChild == null & rightChild == null;
+  }
+
+  /**
+   * Prueft, ob ein Knoten als Vater- oder Kind-Knoten fuer diesen Knoten
+   * verwendet werden kann
+   * @param node zu pruefende Knoten
+   * @exception IllegalArgumentException falls der Knoten nicht geeignet ist
+   */
+  public void checkNode(TreeNode<E> node) {
+    if ( node!=null && !(node instanceof BinaryTreeNode) )
+      throw new IllegalArgumentException("Node must be an BinaryTreeNode!");
+  }
+
+  /**
+   * Liefert die (maximale) Anzahl der Kindknoten.
+   * @return immer 2, unabhaengig davon, ob diese {@code null} sind oder nicht
+   */
+  public int getChildCount() {
+//    int count = 0;
+//    if ( leftChild != null )
+//      count++;
+//    if ( rightChild != null )
+//      count++;
+//    return count;
+      return 2;
+  }
+
+  /**
+   * Liefert einen Kindknoten.
+   * @param i Index (beginnend bei 0)
+   * @return den linken Knoten fuer i = 1, den rechten Knoten sonst
+   */
+  public BinaryTreeNode<E> getChild(int i) {
+    return ( i == 0 ) ? leftChild : rightChild;
+  }
+
+  /**
+   * Setzt einen Kindknoten. Setzt den linken Kind-Knoten fuer i = 1, den rechten
+   * Kind-Knoten sonst
+   * @param i Index (beginnend bei 0)
+   * @exception IllegalArgumentException falls {@code child} kein
+   *            {@code BinaryTreeNode<E>} ist
+   */
+  public void setChild(int i, TreeNode<E> child) {
+    checkNode(child);
+    TreeNode oldChild = null;
+    if ( i == 0 ) {
+      oldChild  = leftChild;
+      leftChild = (BinaryTreeNode<E>)child;
+    } else {
+      oldChild   = rightChild;
+      rightChild = (BinaryTreeNode<E>)child;
+    }
+    // Vater des alten Kind-Konten loeschen
+    if ( oldChild != null )
+      oldChild.setParent(null);
+    // Vater des neuen Kind-Konten setzen
+    if ( child != null )
+      child.setParent(this);
+  }
+
+  /**
+   * Liefert den linken Kindknoten.
+   */
+  public BinaryTreeNode<E> getLeftChild() {
+    return leftChild;
+  }
+
+  /**
+   * Setzt den linken Kindknoten.
+   */
+  public void setLeftChild(BinaryTreeNode<E> child) {
+    setChild(0,child);
+  }
+
+  /**
+   * Liefert den rechten Kindknoten.
+   */
+  public BinaryTreeNode<E> getRightChild() {
+    return rightChild;
+  }
+
+  /**
+   * Setzt den rechten Kindknoten.
+   */
+  public void setRightChild(BinaryTreeNode<E> child) {
+    setChild(1,child);
+  }
+
+  /**
+   * Liefert die im (Teil-)Baum des Knotens gespeicherten Objekte in der
+   * Inorder-Reihenfolge.
+   * @param v Liste in die die Objekte eingefuegt werden (kann {@code null} sein!)
+   */
+  public Vector<E> getObjectsInorder(Vector<E> v) {
+    if ( v == null )
+      v = new Vector<E>();
+
+    if ( leftChild != null )
+      leftChild.getObjectsInorder(v);
+    v.add(this.getObject());
+    if ( rightChild != null )
+      rightChild.getObjectsInorder(v);
+
+    return v;
+  }
+
+  /**
+   * Liefert die im (Teil-)Baum des Knotens gespeicherten Objekte in der
+   * Preorder-Reihenfolge.
+   * @param v Liste in die die Objekte eingefuegt werden (kann {@code null} sein!)
+   */
+  public Vector<E> getObjectsPreorder(Vector<E> v) {
+    if ( v == null )
+      v = new Vector<E>();
+
+    v.add(this.getObject());
+    if ( leftChild != null )
+      leftChild.getObjectsPreorder(v);
+    if ( rightChild != null )
+      rightChild.getObjectsPreorder(v);
+
+    return v;
+  }
+
+  /**
+   * Liefert die im (Teil-)Baum des Knotens gespeicherten Objekte in der
+   * Postorder-Reihenfolge.
+   * @param v Liste in die die Objekte eingefuegt werden (kann {@code null} sein!)
+   */
+  public Vector<E> getObjectsPostorder(Vector<E> v) {
+    if ( v == null )
+      v = new Vector<E>();
+
+    if ( leftChild != null )
+      leftChild.getObjectsPostorder(v);
+    if ( rightChild != null )
+      rightChild.getObjectsPostorder(v);
+    v.add(this.getObject());
+
+    return v;
+  }
+
+}

Modified: trunk/src/schmitzm/lang/tree/OperationTree.java
===================================================================
--- trunk/src/schmitzm/lang/tree/OperationTree.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/lang/tree/OperationTree.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,791 +1,809 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.lang.tree;
-
-import java.util.Random;
-import java.util.regex.Pattern;
-
-import org.apache.log4j.Logger;
-
-import schmitzm.lang.LangUtil;
-
-/**
- * Diese Klasse stellt einen Operator-Baum dar. Dieser unterstuetzt folgende
- * Knoten:<br>
- * <ul>
- *   <li>{@link ConstantNode}: Blatt-Knoten, die einen konstanten Wert darstellen
- *                             (z.B. {@code double} oder {@link String}).</li>
- *   <li>{@link OperatorNode}: Innere Knoten, die fuer einen 2-stelligen Operator
- *       auf dem <i>linken</i> und <i>rechten</i> Sohn stehen:
- *       <ul>
- *         <li>Addition: {@code "+"}</li>
- *         <li>Subtraktion: {@code "-"}</li>
- *         <li>Multiplikation: {@code "*"}</li>
- *         <li>Division: {@code "/"}</li>
- *         <li>Potenzbildung: {@code "^"}</li>
- *         <li>boolesches UND: {@code "&"}</li>
- *         <li>boolesches ODER: {@code "|"}</li>
- *         <li>Gleich: {@code "="} oder {@code "=="}</li>
- *         <li>Ungleich: {@code "!="} oder {@code "<>"}</li>
- *         <li>Kleiner als: {@code "<"}</li>
- *         <li>Groesser als: {@code ">"}</li>
- *         <li>Kleiner gleich: {@code "<="}</li>
- *         <li>Groesser gleich: {@code ">="}</li>
- *         <li>String-Konkatenation: {@code "+"}</li>
- *         <li>Test auf regulaeren Ausdruck: {@code "regex(expression,regular expr)"}</li>
- *         <li>n-tes Ergebnis eines {@linkplain String#split(String) String-Splits} ueber regulaeren Ausdruck: {@code "split(expression,regular expr,n)"}</li>
- *         <li>String-Ersetzung: {@code "replAll(expression,pattern expr,repl expr)"}</li>
- *       </ul></li>
- *   <li>{@link UnaryOperatorNode}: Innere Knoten, die fuer einen 1-stelligen
- *       Operator auf dem <i>linken</i> Sohn stehen:
- *       <ul>
- *         <li>Betrag: {@code "abs(.)"}</li>
- *         <li>Wurzel: {@code "sqr(.)"} oder {@code "sqrt(.)"}</li>
- *         <li>Runden: {@code "rnd(.)"} oder {@code "round(.)"}</li>
- *         <li>Abrunden: {@code "int(.)"} oder {@code "trunc(.)"}</li>
- *         <li>boolesches Nicht: {@code "!(.)"}</li>
- *         <li>Test auf "Not a Number" (NaN): {@code "isNaN(.)"}</li>
- *         <li>Sinus: {@code "sin(.)"}</li>
- *         <li>Cosinus: {@code "cos(.)"}</li>
- *         <li>Tangens: {@code "tan(.)"}</li>
- *         <li>Arcus-Sinus: {@code "arcsin(.)"} oder {@code "asin(.)"}</li>
- *         <li>Arcus-Cosinus: {@code "arccos(.)"} oder {@code "acos(.)"}</li>
- *         <li>Arcus-Tangens: {@code "arctan(.)"} oder {@code "atan(.)"}</li>
- *         <li>Exponentialfunktion: {@code "exp(.)"}</li>
- *         <li>Logarithmus zur Basis e: {@code "ln(.)"}</li>
- *         <li>Logarithmus zur Basis 10: {@code "log(.)"}</li>
- *         <li>Umwandlung Zahl-zu-String: {@code "str(.)"}</li>
- *         <li>Umwandlung String-zu-Zahl: {@code "val(.)"}</li>
- *         <li>Umwandlung in Gross-Buchstaben: {@code "toupper(.)"}</li>
- *         <li>Umwandlung in Klein-Buchstaben: {@code "tolower(.)"}</li>
- *         </ul></li>
- *   <li>{@link ConstantAliasNode}: Blatt-Knoten, die einen Alias fuer eine
- *       Konstante darstellen:
- *       <ul>
- *         <li>Zufallszahl zwischen 0 und 1: {@code "rand"} oder {@code "random"}</li>
- *         <li>"Not a number" (NaN): {@code "NaN"}</li>
- *         <li>Aktuelle Zeit in ms ({@link System#currentTimeMillis()}): {@code "CURR_MILLIS"}</li>
- *       </ul></li>
- *   <li>{@link ITENode}: ITE-Operator:<br>
- *       Der 3-stellige ITE-Operator {@code ITE(.,.,.)} drueckt die Bedingung
- *       "If .. Then .. Else .." aus.</li>
- * </ul>
- * Damit boolesche Operatoren und arithmetische Ausdruecke kombiniert
- * werden koennen, werden die Operanden und das Ergebis einer booleschen
- * Operation nicht als TRUE oder FALSE, sondern numerisch codiert:<br>
- * <b>Operanden:</b> {@code op > 0} entspricht TRUE; {@code op = 0} entspricht FALSE.<br>
- * <b>Ergebnis:</b> TRUE wird als 1 codiert; FALSE wird als 0 codiert.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of  Bonn/Germany)
- * @version 1.0
- */
-public class OperationTree {
-  /** Logger fuer Debug-Ausgaben */
-  protected Logger LOGGER = LangUtil.createLogger(this);
-
-  /** Speichert den Wurzel-Knoten des Operator-Baums. */
-  protected TreeNode rootNode = null;
-
-  /**
-   * Erzeugt einen neuen Operator-Baum.
-   * @param root Wurzelknoten des Baums
-   */
-  protected OperationTree(TreeNode root) {
-    this.rootNode = root;
-  }
-
-  /**
-   * Erzeugt einen neuen Operator-Baum.
-   * @param root Wurzelknoten des Baums
-   */
-  public OperationTree(OperatorNode root) {
-    this((BinaryTreeNode)root);
-  }
-
-  /**
-   * Erzeugt einen neuen Operator-Baum.
-   * @param root Wurzelknoten des Baums
-   */
-  public OperationTree(ConstantNode root) {
-    this((BinaryTreeNode) root);
-  }
-
-  /**
-   * Liefert den Wurzelknoten des Operator-Baums.
-   */
-  public TreeNode getRoot() {
-    return rootNode;
-  }
-
-  /**
-   * Wertet den Operator-Baum aus.
-   */
-  public Object evaluate() {
-    return evaluate(rootNode);
-  }
-
-  /**
-   * Wertet einen Knoten des Operator-Baums aus.
-   * @param opTreeNode BinaryTreeNode
-   */
-  protected Object evaluate(TreeNode opTreeNode) {
-    if ( opTreeNode == null )
-      throw new NullPointerException("null-TreeNode can not be evaluted");
-
-    if ( opTreeNode instanceof ConstantNode )
-      return ((ConstantNode)opTreeNode).getObject();
-
-    if ( opTreeNode instanceof ConstantAliasNode )
-      return performOperation(((ConstantAliasNode)opTreeNode).getObject());
-
-    if ( opTreeNode instanceof UnaryOperatorNode ) {
-      UnaryOperatorNode operatorNode = (UnaryOperatorNode)opTreeNode;
-      String operator = operatorNode.getObject();
-      Object operand  = evaluate( operatorNode.getLeftChild() );
-      return performOperation(operator,operand);
-    }
-
-    if ( opTreeNode instanceof MultiParamOperatorNode ) {
-      MultiParamOperatorNode operatorNode = (MultiParamOperatorNode)opTreeNode;
-      String operator = operatorNode.getObject();
-      // Operanden auswerten
-      Object[] operand = new Object[operatorNode.getChildCount()];
-      for (int i=0; i<operand.length; i++)
-        operand[i] = evaluate( operatorNode.getChild(i) );
-      return performOperation(operator,operand);
-    }
-
-    if ( opTreeNode instanceof ITENode ) {
-      ITENode operatorNode = (ITENode)opTreeNode;
-      Object result = evaluate( operatorNode.getIfNode() );
-      if ( result != null &&
-          (result instanceof Number && ((Number)result).doubleValue() != 0 ||
-           result instanceof Boolean && ((Boolean)result).booleanValue())
-         )
-        return evaluate( operatorNode.getLeftChild() );  // THEN
-      else
-        return evaluate( operatorNode.getRightChild() ); // ELSE
-    }
-
-    if ( opTreeNode instanceof OperatorNode ) {
-      OperatorNode operatorNode = (OperatorNode)opTreeNode;
-      String operator = operatorNode.getObject();
-      Object operand1 = evaluate( operatorNode.getLeftChild() );
-      // Optimierung (2. Operand muss nicht mehr ausgewertet werden!)
-      if ( (operator.equals("*") || operator.equals("/") ) &&
-           (operand1 instanceof Number  && ((Number)operand1).doubleValue() == 0) )
-        return 0;
-      if ( operator.equals("&") &&
-           (operand1 instanceof Number  && ((Number)operand1).doubleValue() == 0 ||
-            operand1 instanceof Boolean && !((Boolean)operand1)) )
-        return 0;
-      if ( operator.equals("|") &&
-           (operand1 instanceof Number  && ((Number)operand1).doubleValue() == 1 ||
-            operand1 instanceof Boolean && ((Boolean)operand1)) )
-        return 1;
-      Object operand2 = evaluate( operatorNode.getRightChild() );
-      return performOperation(operator,operand1,operand2);
-    }
-
-    throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.UnknownNode",opTreeNode.getClass().getName()) );
-  }
-
-  /**
-   * Wertet einen n-stelligen Operator aus. Als Operator unterstuetzt diese
-   * Methode
-   * <ul>
-   *   <li><b>String-Operatoren</b>
-   *       <ul>
-   *         <li>Teil-String: {@code "substr(expression,startPos_incl,endPos_excl)"}</li>
-   *       </ul></li>
-   * </ul>
-   * @param operator n-stelliger Operator
-   * @param operand Operanden auf die der Operator angewandt wird
-   * @exception UnsupportedOperationException falls der Operator {@code null} ist,
-   *            unbekannt ist, oder auf die Operanden nicht angewendet werden kann
-   */
-  protected Object performOperation(String operator, Object[] operand) {
-    if ( operator == null )
-      throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.UnknownOperator",operator) );
-
-    operator = operator.toUpperCase();
-
-    if ( operator.equals("SUBSTR") ) {
-      if ( operand.length < 2 )
-        throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.LessParams1",2,operator) );
-      if ( !(operand[0] instanceof String) )
-        throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.IllegalParam",1,operator,"String") );
-      if ( !(operand[1] instanceof Number) )
-        throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.IllegalParam",2,operator,"Number") );
-      if ( operand.length > 2 && !(operand[2] instanceof Number) )
-        throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.IllegalParam",3,operator,"Number") );
-
-      String str      = (String)operand[0];
-      int    startPos = ((Number)operand[1]).intValue();
-      if ( operand.length < 3 )
-        return str.substring(startPos);
-      int    endPos = ((Number)operand[2]).intValue();
-      return str.substring(startPos, endPos);
-    }
-
-    if ( operator.equals("SPLIT") ) {
-      if ( operand.length < 2 )
-        throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.LessParams1",2,operator) );
-      if ( !(operand[0] instanceof String) )
-        throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.IllegalParam",1,operator,"String") );
-      if ( !(operand[1] instanceof String) )
-        throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.IllegalParam",2,operator,"String") );
-      if ( operand.length > 2 && !(operand[2] instanceof Number) )
-        throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.IllegalParam",3,operator,"Number") );
-
-      String[] result = operand[0].toString().split(operand[1].toString());
-      int      idx    = operand.length > 2 ? ((Number)operand[2]).intValue() : 0;
-      if ( idx < 0 || idx >= result.length )
-        return "";
-      return result[idx];
-    }
-
-    if ( operator.equals("REPLALL") ) {
-      if ( operand.length != 3 )
-        throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.LessParams2",3,operator) );
-      if ( !(operand[0] instanceof String) )
-        throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.IllegalParam",1,operator,"String") );
-      if ( !(operand[1] instanceof String) )
-        throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.IllegalParam",2,operator,"String") );
-      if ( !(operand[2] instanceof String) )
-        throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.IllegalParam",3,operator,"String") );
-
-      String result = operand[0].toString().replaceAll(operand[1].toString(), operand[2].toString());
-      return result;
-    }
-
-    String paramMess = "";
-    for (Object op : operand) {
-      if ( !paramMess.equals("") )
-        paramMess += ", ";
-      paramMess += (op != null) ? op.getClass().getSimpleName() : null;
-    }
-    throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.UnknownOperator",operator+" ("+paramMess+")") );
-}
-
-  /**
-   * Wertet einen 2-stelligen Operator aus. Als Operator unterstuetzt diese
-   * Methode
-   * <ul>
-   *   <li><b>Numerische Operatoren (beide Operatoren numerisch oder boolean)</b>
-   *       <ul>
-   *         <li>Addition: {@code "+"}</li>
-   *         <li>Subtraktion: {@code "-"}</li>
-   *         <li>Multiplikation: {@code "*"}</li>
-   *         <li>Division: {@code "/"}</li>
-   *         <li>Potenzbildung: {@code "^"}</li>
-   *         <li>Boolesches UND: {@code "&"}, {@code "AND"} oder {@code "UND"}</li>
-   *         <li>Boolesches ODER: {@code "|"}, {@code "OR"} oder {@code "ODER"}</li>
-   *       </ul></li>
-   *   <li><b>Vergleichsoperatoren (beide Operatoren vom gleichen Typ!)</b>
-   *       <ul>
-   *         <li>Gleichheit: {@code "=="}, {@code "="} oder {@code "EQ"}</li>
-   *         <li>Ungleichheit: {@code "!="}, {@code "<>"} oder {@code "NE"}</li>
-   *       </ul></li>
-   *   <li><b>Vergleichsoperatoren (beide Operatoren {@link Comparable})</b>
-   *       <ul>
-   *         <li>Kleiner als: {@code "<"} oder {@code "LT"}</li>
-   *         <li>Groesser als: {@code ">"} oder {@code "GT"}</li>
-   *         <li>Kleiner gleich: {@code "<="} oder {@code "LE"}</li>
-   *         <li>Groesser gleich: {@code ">="} oder {@code GE"}</li>
-   *       </ul></li>
-   *   <li><b>String-Operatoren (beide Operatoren String!)</b>
-   *       <ul>
-   *         <li>String-Konkatenation: {@code "+"}</li>
-   *         <li>Test auf regulaeren Ausdruck: {@code "regex(expression,regular expr)"}
-   *       </ul></li>
-   * </ul>
-   * Die boolesche Logik wird im Ergebnis als 1 (TRUE) oder 0 (FALSE) codiert.
-   * Operanden {@code op} werden als FALSE interpretiert, gdw. {@code op == 0}.
-   * @param operator 2-stelliger Operator
-   * @param operand1 linker Operand, auf den der Operator angewendet wird
-   * @param operand2 linker Operand, auf den der Operator angewendet wird
-   * @return {@code op1} <i>operator</i> {@code op2} oder {@code null}, wenn beide
-   *         Operanden {@code null} sind
-   * @exception UnsupportedOperationException falls der Operator {@code null} ist,
-   *            unbekannt ist, oder auf die Operanden nicht angewendet werden kann
-   */
-  protected Object performOperation(String operator, Object operand1, Object operand2) {
-    if ( operand1 == null && operand2 == null )
-      return null;
-    if ( operator == null )
-      throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.UnknownOperator",operator) );
-
-    operator = operator.toUpperCase();
-
-    // numerische und boolesche Operationen
-    if ( (operand1 instanceof Number || operand1 instanceof Boolean) &&
-          operand2 instanceof Number || operand2 instanceof Boolean) {
-      // Operanden in double umwandeln
-      double op1 = operand1 instanceof Number ? ((Number)operand1).doubleValue() : (Boolean)operand1 ? 1 : 0;
-      double op2 = operand2 instanceof Number ? ((Number)operand2).doubleValue() : (Boolean)operand2 ? 1 : 0;
-      if (operator.equals("+"))
-        return op1 + op2;
-      if (operator.equals("-"))
-        return op1 - op2;
-      if (operator.equals("*"))
-        return op1 * op2;
-      if (operator.equals("/"))
-        return op1 / op2;
-      if (operator.equals("^"))
-        return Math.pow(op1, op2);
-      if (operator.equals("&") || operator.equals("AND") || operator.equals("UND"))
-        return op1 != 0 && op2 != 0 ? 1 : 0;
-      if (operator.equals("|") || operator.equals("OR") || operator.equals("ODER"))
-        return op1 != 0 || op2 != 0 ? 1 : 0;
-    }
-
-    // Boolean erst in numerischen Wert umwandeln
-    if ( operand1 instanceof Boolean )
-      operand1 = (Boolean)operand1 ? 1 : 0;
-    if ( operand2 instanceof Boolean )
-      operand2 = (Boolean)operand2 ? 1 : 0;
-    // Vergleichsoperatoren funktionieren nicht korrekt, wenn die Objekte
-    // nicht vom gleichen Typ sind (z.B. Double und Long)
-    // -> in Double umwandeln
-    if ( operand1 instanceof Number )
-      operand1 = ((Number)operand1).doubleValue();
-    if ( operand2 instanceof Number )
-      operand2 = ((Number)operand2).doubleValue();
-
-    // Un/Gleichheit (bei Typ-Gleichheit)
-    if (operator.equals("=") || operator.equals("==") || operator.equals("EQ"))
-      return operand1 != null && operand1.equals(operand2) ||
-             operand2 != null && operand2.equals(operand1) ? 1 : 0;
-    if (operator.equals("!=") || operator.equals("<>") || operator.equals("NE"))
-      return operand1 != null && !operand1.equals(operand2) ||
-             operand2 != null && !operand2.equals(operand1) ? 1 : 0;
-
-    // Vergleichsoperatoren
-    if ( operand1 instanceof Comparable && operand2 instanceof Comparable ) {
-      Comparable op1 = (Comparable)operand1;
-      Comparable op2 = (Comparable)operand2;
-      if (operator.equals(">") || operator.equals("GT"))
-        return op1 != null && op1.compareTo(op2) > 0 ? 1 : 0;
-      if (operator.equals(">=") || operator.equals("GE"))
-        return op1 != null && op1.compareTo(op2) >= 0 ? 1 : 0;
-      if (operator.equals("<") || operator.equalsIgnoreCase("LT"))
-        return op1 != null && op1.compareTo(op2) < 0 ? 1 : 0;
-      if (operator.equals("<=") || operator.equalsIgnoreCase("LE"))
-        return op1 != null && op1.compareTo(op2) <= 0 ? 1 : 0;
-    }
-
-    // String-Operationen
-    if ( operand1 instanceof String || operand2 instanceof String ) {
-      if ( operator.equals("+") )
-        return operand1.toString() + operand2.toString();
-      if ( operator.equals("REGEX") ) {
-//        LOGGER.debug(++i+"   "+operand1);
-//        boolean ret = Pattern.matches(operand2.toString(), operand1.toString());
-        return Pattern.matches(operand2.toString(), operand1.toString()) ? 1 : 0;
-      }
-    }
-
-    String op1Class = (operand1 != null) ? operand1.getClass().getSimpleName() : null;
-    String op2Class = (operand2 != null) ? operand2.getClass().getSimpleName() : null;
-    throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.UnknownOperator",operator+" ("+op1Class+", "+op2Class+")") );
-}
-
-  /**
-   * Wertet einen 1-stelligen Operator aus. Als Operator unterstuetzt diese
-   * Methode
-   * <ul>
-   *   <li><b>Numerische Operatoren (Operand numerisch oder boolean)</b>
-   *       <ul>
-   *         <li>Betrag: {@code "abs(.)"}</li>
-   *         <li>Wurzel: {@code "sqr(.)"} oder {@code "sqrt(.)"}</li>
-   *         <li>Runden: {@code "rnd(.)"} oder {@code "round(.)"}</li>
-   *         <li>Abrunden: {@code "int(.)"} oder {@code "trunc(.)"}</li>
-   *         <li>Boolesches NICHT: {@code "!"}, {@code "NOT"} oder {@code "NICHT"}</li>
-   *         <li>Test auf "Not a Number" (NaN): {@code "isNaN(.)"}</li>
-   *         <li>Sinus: {@code "sin(.)"}</li>
-   *         <li>Cosinus: {@code "cos(.)"}</li>
-   *         <li>Tangens: {@code "tan(.)"}</li>
-   *         <li>Arcus-Sinus: {@code "arcsin(.)"} oder {@code "asin(.)"}</li>
-   *         <li>Arcus-Cosinus: {@code "arccos(.)"} oder {@code "acos(.)"}</li>
-   *         <li>Arcus-Tangens: {@code "arctan(.)"} oder {@code "atan(.)"}</li>
-   *         <li>Exponentialfunktion: {@code "exp(.)"}</li>
-   *         <li>Logarithmus zur Basis e: {@code "ln(.)"}</li>
-   *         <li>Logarithmus zur Basis 10: {@code "log(.)"}</li>
-   *         <li>Umwandlung Zahl-zu-String: {@code "val(.)"}</li>
-   *       </ul></li>
-   *   <li><b>String Operatoren (Operand String)</b>
-   *       <ul>
-   *         <li>Umwandlung String-zu-Zahl: {@code "str(.)"}</li>
-   *         <li>Umwandlung in Gross-Buchstaben: {@code "toupper(.)"}</li>
-   *         <li>Umwandlung in Klein-Buchstaben: {@code "tolower(.)"}</li>
-   *       </ul></li>
-   * </ul>
-   * Die boolesche Logik wird im Ergebnis als 1 (TRUE) oder 0 (FALSE) codiert.
-   * Operanden {@code op} werden als FALSE interpretiert, gdw. {@code op == 0}.
-   * @param operator 1-stelliger Operator
-   * @param operand  Operand auf den der Operator angewendet wird
-   * @return <i>operator</li>( {@code operand} )
-   * @exception UnsupportedOperationException falls der Operator {@code null} ist,
-   *            unbekannt ist, oder auf den Operanden nicht angewendet werden kann
-   */
-  protected Object performOperation(String operator, Object operand) {
-    if ( operator == null )
-      throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.UnknownOperator",operator) );
-
-    operator = operator.toUpperCase();
-
-    // numerische und boolesche Operationen
-    if ( operand instanceof Number || operand instanceof Boolean ) {
-      // Operanden in double umwandeln
-      double op = operand instanceof Number ? ((Number)operand).doubleValue() : (Boolean)operand ? 1 : 0;
-      if ( operator.equals("ISNAN") )
-        return Double.isNaN(op) ? 1: 0;
-      if ( Double.isNaN(op) )
-        return Double.NaN;
-      if ( operator.equals("ABS") )
-        return Math.abs(op);
-      if ( operator.equals("SQR") || operator.equals("SQRT") )
-        return Math.sqrt(op);
-      if (operator.equals("RND") || operator.equals("ROUND"))
-        return Math.round(op);
-      if (operator.equals("INT") || operator.equals("TRUNC"))
-        return (long) op;
-      if (operator.equals("!") || operator.equals("NOT") || operator.equals("NICHT"))
-        return op == 0 ? 1 : 0;
-      if (operator.equals("SIN"))
-        return Math.sin(op);
-      if (operator.equals("COS"))
-        return Math.cos(op);
-      if (operator.equals("TAN"))
-        return Math.tan(op);
-      if (operator.equals("ARCSIN") || operator.equals("ASIN"))
-        return Math.asin(op);
-      if (operator.equals("ARCCOS") || operator.equals("ACOS"))
-        return Math.acos(op);
-      if (operator.equals("ARCTAN") || operator.equals("ATAN"))
-        return Math.atan(op);
-      if (operator.equals("EXP"))
-        return Math.exp(op);
-      if (operator.equals("LOG"))
-        return Math.log10(op);
-      if (operator.equals("LN"))
-        return Math.log(op);
-      if (operator.equals("STR"))
-        return String.valueOf(op);
-    }
-
-    // String Operationen
-    if ( operand instanceof String ) {
-      String op = (String)operand;
-      if (operator.equals("VAL"))
-        return Double.parseDouble(op);
-      if (operator.equals("LEN"))
-        return op.length();
-      if (operator.equals("TOUPPER"))
-        return op.toUpperCase();
-      if (operator.equals("TOLOWER"))
-        return op.toLowerCase();
-    }
-    String opClass = (operand != null) ? operand.getClass().getSimpleName() : null;
-    throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.UnknownOperator",operator+"("+opClass+")") );
-}
-
-  /**
-   * Wertet einen 0-stelligen Operator (Alias oder Variable) aus.
-   * Als Operator unterstuetzt diese Methode
-   * <ul>
-   *   <li>Zufallszahl zwischen 0 und 1: {@code "rand"} oder {@code "random"}</li>
-   * </ul>
-   * @param operator 0-stelliger Operator
-   */
-  protected Object performOperation(String operator) {
-    operator = operator.toUpperCase();
-
-    if ( operator.equals("RAND") || operator.equals("RANDOM") )
-      return new Random().nextDouble();
-    if ( operator.equals("NAN") )
-      return Double.NaN;
-    if ( operator.equals("CURR_MILLIS") )
-      return System.currentTimeMillis();
-    throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.UnknownAliasOperator",operator) );
-  }
-
-  ///////////////////////////////////////////////////////////////////
-  /////////////////   Knoten im Operator-Baum   /////////////////////
-  ///////////////////////////////////////////////////////////////////
-  /**
-   * Diese Knoten repraesentiert einen 2-stelligen Operator im Operatorbaum.
-   * Der Operator wird durch eine Zeichenkette repraesentiert.
-   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-   * @version 1.0
-   */
-  public static class OperatorNode extends BinaryTreeNode<String> {
-    /**
-     * Erzeugt einen neuen Operator-Knoten
-     * @param operator     Operator
-     * @param parent       Vater-Knoten
-     * @param leftOperand  Knoten der den linker Operand repraesentiert
-     * @param rightOperand Knoten der den rechten Operand repraesentiert
-     */
-    public OperatorNode(String operator, BinaryTreeNode parent, BinaryTreeNode leftOperand, BinaryTreeNode rightOperand) {
-      super(operator, parent, leftOperand, rightOperand);
-    }
-
-    /**
-     * Erzeugt einen neuen Operator-Knoten
-     * @param operator     Operator
-     * @param leftOperand  Knoten der den linker Operand repraesentiert
-     * @param rightOperand Knoten der den rechten Operand repraesentiert
-     */
-    public OperatorNode(String operator, BinaryTreeNode leftOperand, BinaryTreeNode rightOperand) {
-      this(operator, null, leftOperand, rightOperand);
-    }
-  }
-
-  /**
-   * Diese Knoten repraesentiert einen 1-stelligen Operator im Operatorbaum.
-   * Dessen rechter Kind-Knoten ist immer {@code null}. Der Operator wird
-   * durch eine Zeichenkette repraesentiert.
-   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-   * @version 1.0
-   */
-  public static class UnaryOperatorNode extends OperatorNode {
-    /**
-     * Erzeugt einen neuen Operator-Knoten
-     * @param operator     Operator
-     * @param parent       Vater-Knoten
-     * @param operand      Knoten der den (linker) Operand repraesentiert
-     */
-    public UnaryOperatorNode(String operator, BinaryTreeNode parent, BinaryTreeNode operand) {
-      super(operator, parent, operand, null);
-    }
-
-    /**
-     * Erzeugt einen neuen Operator-Knoten
-     * @param operator     Operator
-     * @param operand      Knoten der den (linker) Operand repraesentiert
-     */
-    public UnaryOperatorNode(String operator, BinaryTreeNode operand) {
-      this(operator, null, operand);
-    }
-
-    /**
-     * Setzt nur den linken Kind-Knoten. Ist der Parameter {@code i > 0}, wird
-     * der rechte Kind-Knoten auf {@code null} gesetzt, unabhaengig vom
-     * Parameter {@code child}.
-     * @param i Index (beginnend bei 0)
-     * @param child neuer Kind-Knoten
-     */
-    public void setChild(int i, TreeNode<String> child) {
-      if ( i > 0 )
-        child = null;
-      super.setChild(i,child);
-    }
-  }
-
-  /**
-   * Diese Knoten repraesentiert den speziellen Operator ITE
-   * (If-Then-Else) im Operatorbaum. Eigentlich ist dieser Operator 3-stellig.
-   * Um ihn in den binaeren Operator-Baum einzubetten, wird der THEN-Teil im
-   * linken, der ELSE-Teil im rechten Kind und die IF-Bedingung gesondert
-   * im Knoten hinterlegt.
-   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-   * @version 1.0
-   */
-  public static class ITENode extends OperatorNode {
-    /** Speichert die IF-Bedingung des ITE-Operators. */
-    protected TreeNode<String> ifNode = null;
-
-    /**
-     * Erzeugt einen neuen Operator-Knoten
-     * @param operator     Operator
-     * @param parent       Vater-Knoten
-     * @param ifOperand    Knoten der die IF-Bedingung repraesentiert
-     * @param thenOperand  Knoten der die THEN-Auswertung repraesentiert
-     * @param elseOperand  Knoten der die ELSE-Auswertung repraesentiert
-     */
-    public ITENode(String operator, BinaryTreeNode parent, BinaryTreeNode ifOperand, BinaryTreeNode thenOperand, BinaryTreeNode elseOperand) {
-      super(operator, parent, thenOperand, elseOperand);
-      setIfNode(ifOperand);
-    }
-
-    /**
-     * Erzeugt einen neuen Operator-Knoten
-     * @param operator     Operator
-     * @param ifOperand    Knoten der die IF-Bedingung repraesentiert
-     * @param thenOperand  Knoten der die THEN-Auswertung repraesentiert
-     * @param elseOperand  Knoten der die ELSE-Auswertung repraesentiert
-     */
-    public ITENode(String operator, BinaryTreeNode ifOperand, BinaryTreeNode thenOperand, BinaryTreeNode elseOperand) {
-      this(operator, null, ifOperand, thenOperand, elseOperand);
-    }
-
-    /**
-     * Setzt die IF-Bedingung.
-     * @param cond Knoten der die IF-Bedingung repraesentiert
-     */
-    public void setIfNode(TreeNode<String> cond) {
-      ifNode = cond;
-    }
-
-    /**
-     * Liefert einen Knoten, der die IF-Bedingung repraesentiert
-     */
-    public TreeNode<String> getIfNode() {
-      return ifNode;
-    }
-  }
-
-  /**
-   * Diese Knoten repraesentiert den speziellen Operator mit mehr als 2
-   * Operanden.<br>
-   * <b>Bemerkung:<b> Eigentlich "vergewaltigt" dieser Knoten den
-   * {@link BinaryTreeNode} (bzw. {@link OperatorNode}), da er nicht mehr
-   * binaer ist. Ich habe jedoch im Moment keine Zeit, den {@link OperationTreeParser}
-   * so umzuprogrammieren, dass er nur noch auf dem allgemeinen {@link TreeNode}
-   * basiert.
-   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-   * @version 1.0
-   */
-  public static class MultiParamOperatorNode extends OperatorNode {
-    /** Speichert die Parameter des Operators. */
-    protected BinaryTreeNode<String>[] paramNodes = new BinaryTreeNode[0];
-
-    /**
-     * Erzeugt einen neuen Operator-Knoten
-     * @param operator     Operator
-     * @param parent       Vater-Knoten
-     * @param paramCount   Anzahl an Parameters des Operators
-     */
-    public MultiParamOperatorNode(String operator, BinaryTreeNode parent, int paramCount) {
-      super(operator, parent, null, null);
-      paramNodes = new BinaryTreeNode[paramCount];
-    }
-
-    /**
-     * Erzeugt einen neuen Operator-Knoten
-     * @param operator     Operator
-     * @param paramCount   Anzahl an Parameters des Operators
-     */
-    public MultiParamOperatorNode(String operator, int paramCount) {
-      this(operator, null, paramCount);
-    }
-
-    /**
-     * Erzeugt einen neuen Operator-Knoten
-     * @param operator     Operator
-     * @param parent       Vater-Knoten
-     * @param parameter    Knoten die die Funktionsparameter darstellen
-     */
-    public MultiParamOperatorNode(String operator, BinaryTreeNode parent, BinaryTreeNode... parameter) {
-      this(operator, parent, parameter.length);
-      paramNodes = parameter;
-    }
-
-    /**
-     * Setzt den Knoten fuer einen Funktionsparameter.
-     * @param i int Nummer des Parameters
-     * @param paramNode Knoten der den Parameter darstellt
-     */
-    public void setChild(int i, TreeNode<String> paramNode) {
-      checkNode(paramNode);
-      if ( paramNodes != null && i < paramNodes.length )
-        this.paramNodes[i] = (BinaryTreeNode)paramNode;
-    }
-
-    /**
-     * Liefert den Knoten fuer einen Funktionsparameter.
-     * @param i int Nummer des Parameters
-     */
-    public BinaryTreeNode getChild(int i) {
-      return paramNodes != null && i < paramNodes.length ? this.paramNodes[i] : null;
-    }
-
-    /**
-     * Liefert die Anzahl an Parametern.
-     */
-    public int getChildCount() {
-      return paramNodes != null ? this.paramNodes.length : 0;
-    }
-  }
-
-  /**
-   * Diese Knoten repraesentiert einen konstanten Wert
-   * im Operatorbaum. Dessen Kind-Knoten sind immer {@code null}. Der Wert wird
-   * durch einen {@code double} repraesentiert.
-   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-   * @version 1.0
-   */
-  public static class ConstantNode extends BinaryTreeNode {
-    /**
-     * Erzeugt einen neuen Konstanten-Knoten
-     * @param constant Wert der Konstante
-     * @param parent   Vater-Knoten
-     */
-    public ConstantNode(Object constant, BinaryTreeNode parent) {
-      super(constant, parent);
-    }
-
-    /**
-     * Erzeugt einen neuen Konstanten-Knoten
-     * @param constant Wert der Konstante
-     */
-    public ConstantNode(Object constant) {
-      this(constant, null);
-    }
-
-    /**
-     * Macht nichts, da {@code ConstantNode} immer einen Blatt-Knoten darstellt.
-     * @param i Index (beginnend bei 0)
-     * @param child neuer Kind-Knoten
-     */
-    public void setChild(int i, TreeNode child) {
-    }
-  }
-
-  /**
-   * Diese Knoten repraesentiert einen konstanten numerischen Wert
-   * im Operatorbaum, der jedoch nicht direkt, sondern durch einen Alias
-   * dargestellt wird (z.B. "rand" fuer eine Zufallszahl oder ein Variablenname).
-   * Der Knoten hat keine Kind-Knoten (sind immer {@code null}). Der Wert wird
-   * durch einen {@code String} repraesentiert.
-   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-   * @version 1.0
-   */
-  public static class ConstantAliasNode extends BinaryTreeNode<String> {
-    /**
-     * Erzeugt einen neuen Alias-Knoten
-     * @param alias    Alias der Konstante
-     * @param parent   Vater-Knoten
-     */
-    public ConstantAliasNode(String alias, BinaryTreeNode parent) {
-      super(alias, parent);
-    }
-
-    /**
-     * Erzeugt einen neuen Alias-Knoten
-     * @param alias Alias der Konstante
-     */
-    public ConstantAliasNode(String alias) {
-      this(alias, null);
-    }
-
-    /**
-     * Macht nichts, da {@code ConstantAliasNode} immer einen Blatt-Knoten darstellt.
-     * @param i Index (beginnend bei 0)
-     * @param child neuer Kind-Knoten
-     */
-    public void setChild(int i, TreeNode<String> child) {
-    }
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.lang.tree;
+
+import java.util.Random;
+import java.util.regex.Pattern;
+
+import org.apache.log4j.Logger;
+
+import schmitzm.lang.LangUtil;
+
+/**
+ * Diese Klasse stellt einen Operator-Baum dar. Dieser unterstuetzt folgende
+ * Knoten:<br>
+ * <ul>
+ *   <li>{@link ConstantNode}: Blatt-Knoten, die einen konstanten Wert darstellen
+ *                             (z.B. {@code double} oder {@link String}).</li>
+ *   <li>{@link OperatorNode}: Innere Knoten, die fuer einen 2-stelligen Operator
+ *       auf dem <i>linken</i> und <i>rechten</i> Sohn stehen:
+ *       <ul>
+ *         <li>Addition: {@code "+"}</li>
+ *         <li>Subtraktion: {@code "-"}</li>
+ *         <li>Multiplikation: {@code "*"}</li>
+ *         <li>Division: {@code "/"}</li>
+ *         <li>Potenzbildung: {@code "^"}</li>
+ *         <li>boolesches UND: {@code "&"}</li>
+ *         <li>boolesches ODER: {@code "|"}</li>
+ *         <li>Gleich: {@code "="} oder {@code "=="}</li>
+ *         <li>Ungleich: {@code "!="} oder {@code "<>"}</li>
+ *         <li>Kleiner als: {@code "<"}</li>
+ *         <li>Groesser als: {@code ">"}</li>
+ *         <li>Kleiner gleich: {@code "<="}</li>
+ *         <li>Groesser gleich: {@code ">="}</li>
+ *         <li>String-Konkatenation: {@code "+"}</li>
+ *         <li>Test auf regulaeren Ausdruck: {@code "regex(expression,regular expr)"}</li>
+ *         <li>n-tes Ergebnis eines {@linkplain String#split(String) String-Splits} ueber regulaeren Ausdruck: {@code "split(expression,regular expr,n)"}</li>
+ *         <li>String-Ersetzung: {@code "replAll(expression,pattern expr,repl expr)"}</li>
+ *       </ul></li>
+ *   <li>{@link UnaryOperatorNode}: Innere Knoten, die fuer einen 1-stelligen
+ *       Operator auf dem <i>linken</i> Sohn stehen:
+ *       <ul>
+ *         <li>Betrag: {@code "abs(.)"}</li>
+ *         <li>Wurzel: {@code "sqr(.)"} oder {@code "sqrt(.)"}</li>
+ *         <li>Runden: {@code "rnd(.)"} oder {@code "round(.)"}</li>
+ *         <li>Abrunden: {@code "int(.)"} oder {@code "trunc(.)"}</li>
+ *         <li>boolesches Nicht: {@code "!(.)"}</li>
+ *         <li>Test auf "Not a Number" (NaN): {@code "isNaN(.)"}</li>
+ *         <li>Sinus: {@code "sin(.)"}</li>
+ *         <li>Cosinus: {@code "cos(.)"}</li>
+ *         <li>Tangens: {@code "tan(.)"}</li>
+ *         <li>Arcus-Sinus: {@code "arcsin(.)"} oder {@code "asin(.)"}</li>
+ *         <li>Arcus-Cosinus: {@code "arccos(.)"} oder {@code "acos(.)"}</li>
+ *         <li>Arcus-Tangens: {@code "arctan(.)"} oder {@code "atan(.)"}</li>
+ *         <li>Exponentialfunktion: {@code "exp(.)"}</li>
+ *         <li>Logarithmus zur Basis e: {@code "ln(.)"}</li>
+ *         <li>Logarithmus zur Basis 10: {@code "log(.)"}</li>
+ *         <li>Umwandlung Zahl-zu-String: {@code "str(.)"}</li>
+ *         <li>Umwandlung String-zu-Zahl: {@code "val(.)"}</li>
+ *         <li>Umwandlung in Gross-Buchstaben: {@code "toupper(.)"}</li>
+ *         <li>Umwandlung in Klein-Buchstaben: {@code "tolower(.)"}</li>
+ *         </ul></li>
+ *   <li>{@link ConstantAliasNode}: Blatt-Knoten, die einen Alias fuer eine
+ *       Konstante darstellen:
+ *       <ul>
+ *         <li>Zufallszahl zwischen 0 und 1: {@code "rand"} oder {@code "random"}</li>
+ *         <li>"Not a number" (NaN): {@code "NaN"}</li>
+ *         <li>Aktuelle Zeit in ms ({@link System#currentTimeMillis()}): {@code "CURR_MILLIS"}</li>
+ *       </ul></li>
+ *   <li>{@link ITENode}: ITE-Operator:<br>
+ *       Der 3-stellige ITE-Operator {@code ITE(.,.,.)} drueckt die Bedingung
+ *       "If .. Then .. Else .." aus.</li>
+ * </ul>
+ * Damit boolesche Operatoren und arithmetische Ausdruecke kombiniert
+ * werden koennen, werden die Operanden und das Ergebis einer booleschen
+ * Operation nicht als TRUE oder FALSE, sondern numerisch codiert:<br>
+ * <b>Operanden:</b> {@code op > 0} entspricht TRUE; {@code op = 0} entspricht FALSE.<br>
+ * <b>Ergebnis:</b> TRUE wird als 1 codiert; FALSE wird als 0 codiert.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of  Bonn/Germany)
+ * @version 1.0
+ */
+public class OperationTree {
+  /** Logger fuer Debug-Ausgaben */
+  protected Logger LOGGER = LangUtil.createLogger(this);
+
+  /** Speichert den Wurzel-Knoten des Operator-Baums. */
+  protected TreeNode rootNode = null;
+
+  /**
+   * Erzeugt einen neuen Operator-Baum.
+   * @param root Wurzelknoten des Baums
+   */
+  protected OperationTree(TreeNode root) {
+    this.rootNode = root;
+  }
+
+  /**
+   * Erzeugt einen neuen Operator-Baum.
+   * @param root Wurzelknoten des Baums
+   */
+  public OperationTree(OperatorNode root) {
+    this((BinaryTreeNode)root);
+  }
+
+  /**
+   * Erzeugt einen neuen Operator-Baum.
+   * @param root Wurzelknoten des Baums
+   */
+  public OperationTree(ConstantNode root) {
+    this((BinaryTreeNode) root);
+  }
+
+  /**
+   * Liefert den Wurzelknoten des Operator-Baums.
+   */
+  public TreeNode getRoot() {
+    return rootNode;
+  }
+
+  /**
+   * Wertet den Operator-Baum aus.
+   */
+  public Object evaluate() {
+    return evaluate(rootNode);
+  }
+
+  /**
+   * Wertet einen Knoten des Operator-Baums aus.
+   * @param opTreeNode BinaryTreeNode
+   */
+  protected Object evaluate(TreeNode opTreeNode) {
+    if ( opTreeNode == null )
+      throw new NullPointerException("null-TreeNode can not be evaluted");
+
+    if ( opTreeNode instanceof ConstantNode )
+      return ((ConstantNode)opTreeNode).getObject();
+
+    if ( opTreeNode instanceof ConstantAliasNode )
+      return performOperation(((ConstantAliasNode)opTreeNode).getObject());
+
+    if ( opTreeNode instanceof UnaryOperatorNode ) {
+      UnaryOperatorNode operatorNode = (UnaryOperatorNode)opTreeNode;
+      String operator = operatorNode.getObject();
+      Object operand  = evaluate( operatorNode.getLeftChild() );
+      return performOperation(operator,operand);
+    }
+
+    if ( opTreeNode instanceof MultiParamOperatorNode ) {
+      MultiParamOperatorNode operatorNode = (MultiParamOperatorNode)opTreeNode;
+      String operator = operatorNode.getObject();
+      // Operanden auswerten
+      Object[] operand = new Object[operatorNode.getChildCount()];
+      for (int i=0; i<operand.length; i++)
+        operand[i] = evaluate( operatorNode.getChild(i) );
+      return performOperation(operator,operand);
+    }
+
+    if ( opTreeNode instanceof ITENode ) {
+      ITENode operatorNode = (ITENode)opTreeNode;
+      Object result = evaluate( operatorNode.getIfNode() );
+      if ( result != null &&
+          (result instanceof Number && ((Number)result).doubleValue() != 0 ||
+           result instanceof Boolean && ((Boolean)result).booleanValue())
+         )
+        return evaluate( operatorNode.getLeftChild() );  // THEN
+      else
+        return evaluate( operatorNode.getRightChild() ); // ELSE
+    }
+
+    if ( opTreeNode instanceof OperatorNode ) {
+      OperatorNode operatorNode = (OperatorNode)opTreeNode;
+      String operator = operatorNode.getObject();
+      Object operand1 = evaluate( operatorNode.getLeftChild() );
+      // Optimierung (2. Operand muss nicht mehr ausgewertet werden!)
+      if ( (operator.equals("*") || operator.equals("/") ) &&
+           (operand1 instanceof Number  && ((Number)operand1).doubleValue() == 0) )
+        return 0;
+      if ( operator.equals("&") &&
+           (operand1 instanceof Number  && ((Number)operand1).doubleValue() == 0 ||
+            operand1 instanceof Boolean && !((Boolean)operand1)) )
+        return 0;
+      if ( operator.equals("|") &&
+           (operand1 instanceof Number  && ((Number)operand1).doubleValue() == 1 ||
+            operand1 instanceof Boolean && ((Boolean)operand1)) )
+        return 1;
+      Object operand2 = evaluate( operatorNode.getRightChild() );
+      return performOperation(operator,operand1,operand2);
+    }
+
+    throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.UnknownNode",opTreeNode.getClass().getName()) );
+  }
+
+  /**
+   * Wertet einen n-stelligen Operator aus. Als Operator unterstuetzt diese
+   * Methode
+   * <ul>
+   *   <li><b>String-Operatoren</b>
+   *       <ul>
+   *         <li>Teil-String: {@code "substr(expression,startPos_incl,endPos_excl)"}</li>
+   *       </ul></li>
+   * </ul>
+   * @param operator n-stelliger Operator
+   * @param operand Operanden auf die der Operator angewandt wird
+   * @exception UnsupportedOperationException falls der Operator {@code null} ist,
+   *            unbekannt ist, oder auf die Operanden nicht angewendet werden kann
+   */
+  protected Object performOperation(String operator, Object[] operand) {
+    if ( operator == null )
+      throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.UnknownOperator",operator) );
+
+    operator = operator.toUpperCase();
+
+    if ( operator.equals("SUBSTR") ) {
+      if ( operand.length < 2 )
+        throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.LessParams1",2,operator) );
+      if ( !(operand[0] instanceof String) )
+        throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.IllegalParam",1,operator,"String") );
+      if ( !(operand[1] instanceof Number) )
+        throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.IllegalParam",2,operator,"Number") );
+      if ( operand.length > 2 && !(operand[2] instanceof Number) )
+        throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.IllegalParam",3,operator,"Number") );
+
+      String str      = (String)operand[0];
+      int    startPos = ((Number)operand[1]).intValue();
+      if ( operand.length < 3 )
+        return str.substring(startPos);
+      int    endPos = ((Number)operand[2]).intValue();
+      return str.substring(startPos, endPos);
+    }
+
+    if ( operator.equals("SPLIT") ) {
+      if ( operand.length < 2 )
+        throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.LessParams1",2,operator) );
+      if ( !(operand[0] instanceof String) )
+        throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.IllegalParam",1,operator,"String") );
+      if ( !(operand[1] instanceof String) )
+        throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.IllegalParam",2,operator,"String") );
+      if ( operand.length > 2 && !(operand[2] instanceof Number) )
+        throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.IllegalParam",3,operator,"Number") );
+
+      String[] result = operand[0].toString().split(operand[1].toString());
+      int      idx    = operand.length > 2 ? ((Number)operand[2]).intValue() : 0;
+      if ( idx < 0 || idx >= result.length )
+        return "";
+      return result[idx];
+    }
+
+    if ( operator.equals("REPLALL") ) {
+      if ( operand.length != 3 )
+        throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.LessParams2",3,operator) );
+      if ( !(operand[0] instanceof String) )
+        throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.IllegalParam",1,operator,"String") );
+      if ( !(operand[1] instanceof String) )
+        throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.IllegalParam",2,operator,"String") );
+      if ( !(operand[2] instanceof String) )
+        throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.IllegalParam",3,operator,"String") );
+
+      String result = operand[0].toString().replaceAll(operand[1].toString(), operand[2].toString());
+      return result;
+    }
+
+    String paramMess = "";
+    for (Object op : operand) {
+      if ( !paramMess.equals("") )
+        paramMess += ", ";
+      paramMess += (op != null) ? op.getClass().getSimpleName() : null;
+    }
+    throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.UnknownOperator",operator+" ("+paramMess+")") );
+}
+
+  /**
+   * Wertet einen 2-stelligen Operator aus. Als Operator unterstuetzt diese
+   * Methode
+   * <ul>
+   *   <li><b>Numerische Operatoren (beide Operatoren numerisch oder boolean)</b>
+   *       <ul>
+   *         <li>Addition: {@code "+"}</li>
+   *         <li>Subtraktion: {@code "-"}</li>
+   *         <li>Multiplikation: {@code "*"}</li>
+   *         <li>Division: {@code "/"}</li>
+   *         <li>Potenzbildung: {@code "^"}</li>
+   *         <li>Boolesches UND: {@code "&"}, {@code "AND"} oder {@code "UND"}</li>
+   *         <li>Boolesches ODER: {@code "|"}, {@code "OR"} oder {@code "ODER"}</li>
+   *       </ul></li>
+   *   <li><b>Vergleichsoperatoren (beide Operatoren vom gleichen Typ!)</b>
+   *       <ul>
+   *         <li>Gleichheit: {@code "=="}, {@code "="} oder {@code "EQ"}</li>
+   *         <li>Ungleichheit: {@code "!="}, {@code "<>"} oder {@code "NE"}</li>
+   *       </ul></li>
+   *   <li><b>Vergleichsoperatoren (beide Operatoren {@link Comparable})</b>
+   *       <ul>
+   *         <li>Kleiner als: {@code "<"} oder {@code "LT"}</li>
+   *         <li>Groesser als: {@code ">"} oder {@code "GT"}</li>
+   *         <li>Kleiner gleich: {@code "<="} oder {@code "LE"}</li>
+   *         <li>Groesser gleich: {@code ">="} oder {@code GE"}</li>
+   *       </ul></li>
+   *   <li><b>String-Operatoren (beide Operatoren String!)</b>
+   *       <ul>
+   *         <li>String-Konkatenation: {@code "+"}</li>
+   *         <li>Test auf regulaeren Ausdruck: {@code "regex(expression,regular expr)"}
+   *       </ul></li>
+   * </ul>
+   * Die boolesche Logik wird im Ergebnis als 1 (TRUE) oder 0 (FALSE) codiert.
+   * Operanden {@code op} werden als FALSE interpretiert, gdw. {@code op == 0}.
+   * @param operator 2-stelliger Operator
+   * @param operand1 linker Operand, auf den der Operator angewendet wird
+   * @param operand2 linker Operand, auf den der Operator angewendet wird
+   * @return {@code op1} <i>operator</i> {@code op2} oder {@code null}, wenn beide
+   *         Operanden {@code null} sind
+   * @exception UnsupportedOperationException falls der Operator {@code null} ist,
+   *            unbekannt ist, oder auf die Operanden nicht angewendet werden kann
+   */
+  protected Object performOperation(String operator, Object operand1, Object operand2) {
+    if ( operand1 == null && operand2 == null )
+      return null;
+    if ( operator == null )
+      throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.UnknownOperator",operator) );
+
+    operator = operator.toUpperCase();
+
+    // numerische und boolesche Operationen
+    if ( (operand1 instanceof Number || operand1 instanceof Boolean) &&
+          operand2 instanceof Number || operand2 instanceof Boolean) {
+      // Operanden in double umwandeln
+      double op1 = operand1 instanceof Number ? ((Number)operand1).doubleValue() : (Boolean)operand1 ? 1 : 0;
+      double op2 = operand2 instanceof Number ? ((Number)operand2).doubleValue() : (Boolean)operand2 ? 1 : 0;
+      if (operator.equals("+"))
+        return op1 + op2;
+      if (operator.equals("-"))
+        return op1 - op2;
+      if (operator.equals("*"))
+        return op1 * op2;
+      if (operator.equals("/"))
+        return op1 / op2;
+      if (operator.equals("^"))
+        return Math.pow(op1, op2);
+      if (operator.equals("&") || operator.equals("AND") || operator.equals("UND"))
+        return op1 != 0 && op2 != 0 ? 1 : 0;
+      if (operator.equals("|") || operator.equals("OR") || operator.equals("ODER"))
+        return op1 != 0 || op2 != 0 ? 1 : 0;
+    }
+
+    // Boolean erst in numerischen Wert umwandeln
+    if ( operand1 instanceof Boolean )
+      operand1 = (Boolean)operand1 ? 1 : 0;
+    if ( operand2 instanceof Boolean )
+      operand2 = (Boolean)operand2 ? 1 : 0;
+    // Vergleichsoperatoren funktionieren nicht korrekt, wenn die Objekte
+    // nicht vom gleichen Typ sind (z.B. Double und Long)
+    // -> in Double umwandeln
+    if ( operand1 instanceof Number )
+      operand1 = ((Number)operand1).doubleValue();
+    if ( operand2 instanceof Number )
+      operand2 = ((Number)operand2).doubleValue();
+
+    // Un/Gleichheit (bei Typ-Gleichheit)
+    if (operator.equals("=") || operator.equals("==") || operator.equals("EQ"))
+      return operand1 != null && operand1.equals(operand2) ||
+             operand2 != null && operand2.equals(operand1) ? 1 : 0;
+    if (operator.equals("!=") || operator.equals("<>") || operator.equals("NE"))
+      return operand1 != null && !operand1.equals(operand2) ||
+             operand2 != null && !operand2.equals(operand1) ? 1 : 0;
+
+    // Vergleichsoperatoren
+    if ( operand1 instanceof Comparable && operand2 instanceof Comparable ) {
+      Comparable op1 = (Comparable)operand1;
+      Comparable op2 = (Comparable)operand2;
+      if (operator.equals(">") || operator.equals("GT"))
+        return op1 != null && op1.compareTo(op2) > 0 ? 1 : 0;
+      if (operator.equals(">=") || operator.equals("GE"))
+        return op1 != null && op1.compareTo(op2) >= 0 ? 1 : 0;
+      if (operator.equals("<") || operator.equalsIgnoreCase("LT"))
+        return op1 != null && op1.compareTo(op2) < 0 ? 1 : 0;
+      if (operator.equals("<=") || operator.equalsIgnoreCase("LE"))
+        return op1 != null && op1.compareTo(op2) <= 0 ? 1 : 0;
+    }
+
+    // String-Operationen
+    if ( operand1 instanceof String || operand2 instanceof String ) {
+      if ( operator.equals("+") )
+        return operand1.toString() + operand2.toString();
+      if ( operator.equals("REGEX") ) {
+//        LOGGER.debug(++i+"   "+operand1);
+//        boolean ret = Pattern.matches(operand2.toString(), operand1.toString());
+        return Pattern.matches(operand2.toString(), operand1.toString()) ? 1 : 0;
+      }
+    }
+
+    String op1Class = (operand1 != null) ? operand1.getClass().getSimpleName() : null;
+    String op2Class = (operand2 != null) ? operand2.getClass().getSimpleName() : null;
+    throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.UnknownOperator",operator+" ("+op1Class+", "+op2Class+")") );
+}
+
+  /**
+   * Wertet einen 1-stelligen Operator aus. Als Operator unterstuetzt diese
+   * Methode
+   * <ul>
+   *   <li><b>Numerische Operatoren (Operand numerisch oder boolean)</b>
+   *       <ul>
+   *         <li>Betrag: {@code "abs(.)"}</li>
+   *         <li>Wurzel: {@code "sqr(.)"} oder {@code "sqrt(.)"}</li>
+   *         <li>Runden: {@code "rnd(.)"} oder {@code "round(.)"}</li>
+   *         <li>Abrunden: {@code "int(.)"} oder {@code "trunc(.)"}</li>
+   *         <li>Boolesches NICHT: {@code "!"}, {@code "NOT"} oder {@code "NICHT"}</li>
+   *         <li>Test auf "Not a Number" (NaN): {@code "isNaN(.)"}</li>
+   *         <li>Sinus: {@code "sin(.)"}</li>
+   *         <li>Cosinus: {@code "cos(.)"}</li>
+   *         <li>Tangens: {@code "tan(.)"}</li>
+   *         <li>Arcus-Sinus: {@code "arcsin(.)"} oder {@code "asin(.)"}</li>
+   *         <li>Arcus-Cosinus: {@code "arccos(.)"} oder {@code "acos(.)"}</li>
+   *         <li>Arcus-Tangens: {@code "arctan(.)"} oder {@code "atan(.)"}</li>
+   *         <li>Exponentialfunktion: {@code "exp(.)"}</li>
+   *         <li>Logarithmus zur Basis e: {@code "ln(.)"}</li>
+   *         <li>Logarithmus zur Basis 10: {@code "log(.)"}</li>
+   *         <li>Umwandlung Zahl-zu-String: {@code "val(.)"}</li>
+   *       </ul></li>
+   *   <li><b>String Operatoren (Operand String)</b>
+   *       <ul>
+   *         <li>Umwandlung String-zu-Zahl: {@code "str(.)"}</li>
+   *         <li>Umwandlung in Gross-Buchstaben: {@code "toupper(.)"}</li>
+   *         <li>Umwandlung in Klein-Buchstaben: {@code "tolower(.)"}</li>
+   *       </ul></li>
+   * </ul>
+   * Die boolesche Logik wird im Ergebnis als 1 (TRUE) oder 0 (FALSE) codiert.
+   * Operanden {@code op} werden als FALSE interpretiert, gdw. {@code op == 0}.
+   * @param operator 1-stelliger Operator
+   * @param operand  Operand auf den der Operator angewendet wird
+   * @return <i>operator</li>( {@code operand} )
+   * @exception UnsupportedOperationException falls der Operator {@code null} ist,
+   *            unbekannt ist, oder auf den Operanden nicht angewendet werden kann
+   */
+  protected Object performOperation(String operator, Object operand) {
+    if ( operator == null )
+      throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.UnknownOperator",operator) );
+
+    operator = operator.toUpperCase();
+
+    // numerische und boolesche Operationen
+    if ( operand instanceof Number || operand instanceof Boolean ) {
+      // Operanden in double umwandeln
+      double op = operand instanceof Number ? ((Number)operand).doubleValue() : (Boolean)operand ? 1 : 0;
+      if ( operator.equals("ISNAN") )
+        return Double.isNaN(op) ? 1: 0;
+      if ( Double.isNaN(op) )
+        return Double.NaN;
+      if ( operator.equals("ABS") )
+        return Math.abs(op);
+      if ( operator.equals("SQR") || operator.equals("SQRT") )
+        return Math.sqrt(op);
+      if (operator.equals("RND") || operator.equals("ROUND"))
+        return Math.round(op);
+      if (operator.equals("INT") || operator.equals("TRUNC"))
+        return (long) op;
+      if (operator.equals("!") || operator.equals("NOT") || operator.equals("NICHT"))
+        return op == 0 ? 1 : 0;
+      if (operator.equals("SIN"))
+        return Math.sin(op);
+      if (operator.equals("COS"))
+        return Math.cos(op);
+      if (operator.equals("TAN"))
+        return Math.tan(op);
+      if (operator.equals("ARCSIN") || operator.equals("ASIN"))
+        return Math.asin(op);
+      if (operator.equals("ARCCOS") || operator.equals("ACOS"))
+        return Math.acos(op);
+      if (operator.equals("ARCTAN") || operator.equals("ATAN"))
+        return Math.atan(op);
+      if (operator.equals("EXP"))
+        return Math.exp(op);
+      if (operator.equals("LOG"))
+        return Math.log10(op);
+      if (operator.equals("LN"))
+        return Math.log(op);
+      if (operator.equals("STR"))
+        return String.valueOf(op);
+    }
+
+    // String Operationen
+    if ( operand instanceof String ) {
+      String op = (String)operand;
+      if (operator.equals("VAL"))
+        return Double.parseDouble(op);
+      if (operator.equals("LEN"))
+        return op.length();
+      if (operator.equals("TOUPPER"))
+        return op.toUpperCase();
+      if (operator.equals("TOLOWER"))
+        return op.toLowerCase();
+    }
+    String opClass = (operand != null) ? operand.getClass().getSimpleName() : null;
+    throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.UnknownOperator",operator+"("+opClass+")") );
+}
+
+  /**
+   * Wertet einen 0-stelligen Operator (Alias oder Variable) aus.
+   * Als Operator unterstuetzt diese Methode
+   * <ul>
+   *   <li>Zufallszahl zwischen 0 und 1: {@code "rand"} oder {@code "random"}</li>
+   * </ul>
+   * @param operator 0-stelliger Operator
+   */
+  protected Object performOperation(String operator) {
+    operator = operator.toUpperCase();
+
+    if ( operator.equals("RAND") || operator.equals("RANDOM") )
+      return new Random().nextDouble();
+    if ( operator.equals("NAN") )
+      return Double.NaN;
+    if ( operator.equals("CURR_MILLIS") )
+      return System.currentTimeMillis();
+    throw new UnsupportedOperationException( LangUtil.RESOURCE.getString("OperationTree.err.UnknownAliasOperator",operator) );
+  }
+
+  ///////////////////////////////////////////////////////////////////
+  /////////////////   Knoten im Operator-Baum   /////////////////////
+  ///////////////////////////////////////////////////////////////////
+  /**
+   * Diese Knoten repraesentiert einen 2-stelligen Operator im Operatorbaum.
+   * Der Operator wird durch eine Zeichenkette repraesentiert.
+   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+   * @version 1.0
+   */
+  public static class OperatorNode extends BinaryTreeNode<String> {
+    /**
+     * Erzeugt einen neuen Operator-Knoten
+     * @param operator     Operator
+     * @param parent       Vater-Knoten
+     * @param leftOperand  Knoten der den linker Operand repraesentiert
+     * @param rightOperand Knoten der den rechten Operand repraesentiert
+     */
+    public OperatorNode(String operator, BinaryTreeNode parent, BinaryTreeNode leftOperand, BinaryTreeNode rightOperand) {
+      super(operator, parent, leftOperand, rightOperand);
+    }
+
+    /**
+     * Erzeugt einen neuen Operator-Knoten
+     * @param operator     Operator
+     * @param leftOperand  Knoten der den linker Operand repraesentiert
+     * @param rightOperand Knoten der den rechten Operand repraesentiert
+     */
+    public OperatorNode(String operator, BinaryTreeNode leftOperand, BinaryTreeNode rightOperand) {
+      this(operator, null, leftOperand, rightOperand);
+    }
+  }
+
+  /**
+   * Diese Knoten repraesentiert einen 1-stelligen Operator im Operatorbaum.
+   * Dessen rechter Kind-Knoten ist immer {@code null}. Der Operator wird
+   * durch eine Zeichenkette repraesentiert.
+   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+   * @version 1.0
+   */
+  public static class UnaryOperatorNode extends OperatorNode {
+    /**
+     * Erzeugt einen neuen Operator-Knoten
+     * @param operator     Operator
+     * @param parent       Vater-Knoten
+     * @param operand      Knoten der den (linker) Operand repraesentiert
+     */
+    public UnaryOperatorNode(String operator, BinaryTreeNode parent, BinaryTreeNode operand) {
+      super(operator, parent, operand, null);
+    }
+
+    /**
+     * Erzeugt einen neuen Operator-Knoten
+     * @param operator     Operator
+     * @param operand      Knoten der den (linker) Operand repraesentiert
+     */
+    public UnaryOperatorNode(String operator, BinaryTreeNode operand) {
+      this(operator, null, operand);
+    }
+
+    /**
+     * Setzt nur den linken Kind-Knoten. Ist der Parameter {@code i > 0}, wird
+     * der rechte Kind-Knoten auf {@code null} gesetzt, unabhaengig vom
+     * Parameter {@code child}.
+     * @param i Index (beginnend bei 0)
+     * @param child neuer Kind-Knoten
+     */
+    public void setChild(int i, TreeNode<String> child) {
+      if ( i > 0 )
+        child = null;
+      super.setChild(i,child);
+    }
+  }
+
+  /**
+   * Diese Knoten repraesentiert den speziellen Operator ITE
+   * (If-Then-Else) im Operatorbaum. Eigentlich ist dieser Operator 3-stellig.
+   * Um ihn in den binaeren Operator-Baum einzubetten, wird der THEN-Teil im
+   * linken, der ELSE-Teil im rechten Kind und die IF-Bedingung gesondert
+   * im Knoten hinterlegt.
+   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+   * @version 1.0
+   */
+  public static class ITENode extends OperatorNode {
+    /** Speichert die IF-Bedingung des ITE-Operators. */
+    protected TreeNode<String> ifNode = null;
+
+    /**
+     * Erzeugt einen neuen Operator-Knoten
+     * @param operator     Operator
+     * @param parent       Vater-Knoten
+     * @param ifOperand    Knoten der die IF-Bedingung repraesentiert
+     * @param thenOperand  Knoten der die THEN-Auswertung repraesentiert
+     * @param elseOperand  Knoten der die ELSE-Auswertung repraesentiert
+     */
+    public ITENode(String operator, BinaryTreeNode parent, BinaryTreeNode ifOperand, BinaryTreeNode thenOperand, BinaryTreeNode elseOperand) {
+      super(operator, parent, thenOperand, elseOperand);
+      setIfNode(ifOperand);
+    }
+
+    /**
+     * Erzeugt einen neuen Operator-Knoten
+     * @param operator     Operator
+     * @param ifOperand    Knoten der die IF-Bedingung repraesentiert
+     * @param thenOperand  Knoten der die THEN-Auswertung repraesentiert
+     * @param elseOperand  Knoten der die ELSE-Auswertung repraesentiert
+     */
+    public ITENode(String operator, BinaryTreeNode ifOperand, BinaryTreeNode thenOperand, BinaryTreeNode elseOperand) {
+      this(operator, null, ifOperand, thenOperand, elseOperand);
+    }
+
+    /**
+     * Setzt die IF-Bedingung.
+     * @param cond Knoten der die IF-Bedingung repraesentiert
+     */
+    public void setIfNode(TreeNode<String> cond) {
+      ifNode = cond;
+    }
+
+    /**
+     * Liefert einen Knoten, der die IF-Bedingung repraesentiert
+     */
+    public TreeNode<String> getIfNode() {
+      return ifNode;
+    }
+  }
+
+  /**
+   * Diese Knoten repraesentiert den speziellen Operator mit mehr als 2
+   * Operanden.<br>
+   * <b>Bemerkung:<b> Eigentlich "vergewaltigt" dieser Knoten den
+   * {@link BinaryTreeNode} (bzw. {@link OperatorNode}), da er nicht mehr
+   * binaer ist. Ich habe jedoch im Moment keine Zeit, den {@link OperationTreeParser}
+   * so umzuprogrammieren, dass er nur noch auf dem allgemeinen {@link TreeNode}
+   * basiert.
+   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+   * @version 1.0
+   */
+  public static class MultiParamOperatorNode extends OperatorNode {
+    /** Speichert die Parameter des Operators. */
+    protected BinaryTreeNode<String>[] paramNodes = new BinaryTreeNode[0];
+
+    /**
+     * Erzeugt einen neuen Operator-Knoten
+     * @param operator     Operator
+     * @param parent       Vater-Knoten
+     * @param paramCount   Anzahl an Parameters des Operators
+     */
+    public MultiParamOperatorNode(String operator, BinaryTreeNode parent, int paramCount) {
+      super(operator, parent, null, null);
+      paramNodes = new BinaryTreeNode[paramCount];
+    }
+
+    /**
+     * Erzeugt einen neuen Operator-Knoten
+     * @param operator     Operator
+     * @param paramCount   Anzahl an Parameters des Operators
+     */
+    public MultiParamOperatorNode(String operator, int paramCount) {
+      this(operator, null, paramCount);
+    }
+
+    /**
+     * Erzeugt einen neuen Operator-Knoten
+     * @param operator     Operator
+     * @param parent       Vater-Knoten
+     * @param parameter    Knoten die die Funktionsparameter darstellen
+     */
+    public MultiParamOperatorNode(String operator, BinaryTreeNode parent, BinaryTreeNode... parameter) {
+      this(operator, parent, parameter.length);
+      paramNodes = parameter;
+    }
+
+    /**
+     * Setzt den Knoten fuer einen Funktionsparameter.
+     * @param i int Nummer des Parameters
+     * @param paramNode Knoten der den Parameter darstellt
+     */
+    public void setChild(int i, TreeNode<String> paramNode) {
+      checkNode(paramNode);
+      if ( paramNodes != null && i < paramNodes.length )
+        this.paramNodes[i] = (BinaryTreeNode)paramNode;
+    }
+
+    /**
+     * Liefert den Knoten fuer einen Funktionsparameter.
+     * @param i int Nummer des Parameters
+     */
+    public BinaryTreeNode getChild(int i) {
+      return paramNodes != null && i < paramNodes.length ? this.paramNodes[i] : null;
+    }
+
+    /**
+     * Liefert die Anzahl an Parametern.
+     */
+    public int getChildCount() {
+      return paramNodes != null ? this.paramNodes.length : 0;
+    }
+  }
+
+  /**
+   * Diese Knoten repraesentiert einen konstanten Wert
+   * im Operatorbaum. Dessen Kind-Knoten sind immer {@code null}. Der Wert wird
+   * durch einen {@code double} repraesentiert.
+   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+   * @version 1.0
+   */
+  public static class ConstantNode extends BinaryTreeNode {
+    /**
+     * Erzeugt einen neuen Konstanten-Knoten
+     * @param constant Wert der Konstante
+     * @param parent   Vater-Knoten
+     */
+    public ConstantNode(Object constant, BinaryTreeNode parent) {
+      super(constant, parent);
+    }
+
+    /**
+     * Erzeugt einen neuen Konstanten-Knoten
+     * @param constant Wert der Konstante
+     */
+    public ConstantNode(Object constant) {
+      this(constant, null);
+    }
+
+    /**
+     * Macht nichts, da {@code ConstantNode} immer einen Blatt-Knoten darstellt.
+     * @param i Index (beginnend bei 0)
+     * @param child neuer Kind-Knoten
+     */
+    public void setChild(int i, TreeNode child) {
+    }
+  }
+
+  /**
+   * Diese Knoten repraesentiert einen konstanten numerischen Wert
+   * im Operatorbaum, der jedoch nicht direkt, sondern durch einen Alias
+   * dargestellt wird (z.B. "rand" fuer eine Zufallszahl oder ein Variablenname).
+   * Der Knoten hat keine Kind-Knoten (sind immer {@code null}). Der Wert wird
+   * durch einen {@code String} repraesentiert.
+   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+   * @version 1.0
+   */
+  public static class ConstantAliasNode extends BinaryTreeNode<String> {
+    /**
+     * Erzeugt einen neuen Alias-Knoten
+     * @param alias    Alias der Konstante
+     * @param parent   Vater-Knoten
+     */
+    public ConstantAliasNode(String alias, BinaryTreeNode parent) {
+      super(alias, parent);
+    }
+
+    /**
+     * Erzeugt einen neuen Alias-Knoten
+     * @param alias Alias der Konstante
+     */
+    public ConstantAliasNode(String alias) {
+      this(alias, null);
+    }
+
+    /**
+     * Macht nichts, da {@code ConstantAliasNode} immer einen Blatt-Knoten darstellt.
+     * @param i Index (beginnend bei 0)
+     * @param child neuer Kind-Knoten
+     */
+    public void setChild(int i, TreeNode<String> child) {
+    }
+  }
+
+}

Modified: trunk/src/schmitzm/lang/tree/OperationTreeParser.java
===================================================================
--- trunk/src/schmitzm/lang/tree/OperationTreeParser.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/lang/tree/OperationTreeParser.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,1121 +1,1139 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.lang.tree;
-
-import java.util.NoSuchElementException;
-
-import org.apache.log4j.Logger;
-
-import schmitzm.lang.LangUtil;
-import schmitzm.lang.PushbackStringTokenizer;
-import schmitzm.lang.tree.OperationTree.ConstantAliasNode;
-import schmitzm.lang.tree.OperationTree.ConstantNode;
-import schmitzm.lang.tree.OperationTree.ITENode;
-import schmitzm.lang.tree.OperationTree.MultiParamOperatorNode;
-import schmitzm.lang.tree.OperationTree.OperatorNode;
-import schmitzm.lang.tree.OperationTree.UnaryOperatorNode;
-
-/**
- * Diese Klasse stellt einen Parser fuer einen {@linkplain OperationTree Operator-Baum}
- * dar. Dieser erstellt einen {@linkplain OperationTree Operator-Baum} aus einem
- * Formel-String, der folgende Teilen bestehen darf:
- * <ul>
- *   <li>konstante numerische Werte: {@link ConstantNode}</li>
- *       <ul>
- *           <li>Zahlen im {@code double}-Bereich</li>
- *           <li>{@code rand} oder {@code random} als Alias fuer eine Zufallszahl
- *                zwischen 0 und 1: {@link ConstantAliasNode}</li>
- *           <li>"Not a number" (NaN): {@code "NaN"}</li>
- *           <li>boolesches WAHR (1): {@code "TRUE"}</li>
- *           <li>boolesches FALSCH (0): {@code "FALSE"}</li>
- *           <li>Aktuelle Zeit in ms ({@link System#currentTimeMillis()}): {@code "CURR_MILLIS"}</li>
- *       </ul></li>
- *   <li>konstante String Werte: {@link ConstantNode}</li>
- *       <ul>
- *           <li>Zeichenketten, die durch " oder ' eingeleitet und abgeschlossen
- *               werden</li>
- *       </ul></li>
- *   <li>den 2-stelligen arithmetischen Operatoren: {@link OperatorNode}
- *       <ul>
- *          <li>Addition: {@code "+"}</li>
- *          <li>Subtraktion: {@code "-"}</li>
- *          <li>Multiplikation: {@code "*"}</li>
- *          <li>Division: {@code "/"}</li>
- *          <li>Potenzbildung: {@code "^"}</li>
- *        </ul></li>
- *   <li>den 2-stelligen booleschen Operatoren: {@link OperatorNode}
- *       <ul>
- *          <li>boolesches UND: {@code "&"}</li>
- *          <li>boolesches ODER: {@code "|"}</li>
- *          <li>Gleich: {@code "="} oder {@code "=="}</li>
- *          <li>Ungleich: {@code "!="} oder {@code "<>"}</li>
- *          <li>Kleiner als: {@code "<"}</li>
- *          <li>Groesser als: {@code ">"}</li>
- *          <li>Kleiner gleich: {@code "<="}</li>
- *          <li>Groesser gleich: {@code ">="}</li>
- *        </ul></li>
- *   <li>den 2-stelligen Zeichenketten-Operatoren: {@link OperatorNode}
- *       <ul>
- *          <li>String-Konkatenation: {@code "+"}</li>
- *          <li>Test auf regulaeren Ausdruck: {@code "regex(expression,regular expr)"}</li>
- *          <li>n-tes Ergebnis eines {@linkplain String#split(String) String-Splits} ueber regulaeren Ausdruck: {@code "split(expression,regular expr,n)"}</li>
- *       </ul></li>
- *   <li>den mehr-stelligen Zeichenketten-Operatoren: {@link MultiParamOperatorNode}
- *       <ul>
- *          <li>Teil-String: {@code "substr(expression,startPos_inkl,endPos_exkl)"}</li>
- *          <li>String-Ersetzung: {@code "replAll(expression,pattern,replacement)"}</li>
- *       </ul></li>
- *   <li>die 1-stelligen Operatoren: {@link UnaryOperatorNode}
- *       <ul>
- *          <li>Betrag: {@code "abs(.)"}</li>
- *          <li>Wurzel: {@code "sqr(.)"} oder {@code "sqrt(.)"}</li>
- *          <li>Runden: {@code "rnd(.)"} oder {@code "round(.)"}</li>
- *          <li>Abschneiden: {@code "int(.)"} oder {@code "trunc(.)"}</li>
- *          <li>Test auf "Not a Number" (NaN): {@code "isNaN(.)"}</li>
- *          <li>Sinus: {@code "sin(.)"}</li>
- *          <li>Cosinus: {@code "cos(.)"}</li>
- *          <li>Tangens: {@code "tan(.)"}</li>
- *          <li>Arcus-Sinus: {@code "arcsin(.)"} oder {@code "asin(.)"}</li>
- *          <li>Arcus-Cosinus: {@code "arccos(.)"} oder {@code "acos(.)"}</li>
- *          <li>Arcus-Tangens: {@code "arctan(.)"} oder {@code "atan(.)"}</li>
- *          <li>Exponentialfunktion: {@code "exp(.)"}</li>
- *          <li>Logarithmus zur Basis e: {@code "ln(.)"}</li>
- *          <li>Logarithmus zur Basis 10: {@code "log(.)"}</li>
- *        </ul></li>
- *   <li>den 1-stelligen booleschen Operatoren: {@link UnaryOperatorNode}
- *       <ul>
- *          <li>boolesches NICHT: {@code "!(.)"}</li>
- *        </ul></li>
- *   <li>den 1-stelligen String-Operatoren: {@link UnaryOperatorNode}
- *       <ul>
- *          <li>Umwandlung Zahl-zu-String: {@code "str(.)"}</li>
- *          <li>Umwandlung String-zu-Zahl: {@code "val(.)"}</li>
- *          <li>Umwandlung in Gross-Buchstaben: {@code "toupper(.)"}</li>
- *          <li>Umwandlung in Klein-Buchstaben: {@code "tolower(.)"}</li>
- *          <li>Laenge eines Strings: {@code "len(.)"}</li>
- *        </ul></li>
- *   <li>dem 3-stelligen Operator {@code ITE(.,.,.)}: {@link ITENode}<br>
- *       Der ITE-Operator drueckt eine Bedingung "IF .. THEN .. ELSE .." aus.</li>
- * </ul>
- * <br>
- * Damit boolesche Operatoren und arithmetische Ausdruecke kombiniert
- * werden koennen, werden die Operanden und das Ergebis einer booleschen
- * Operation nicht als TRUE oder FALSE, sondern numerisch codiert:<br>
- * <b>Operanden:</b> {@code op > 0} entspricht TRUE; {@code op = 0} entspricht FALSE.<br>
- * <b>Ergebnis:</b> TRUE wird als 1 codiert; FALSE wird als 0 codiert.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class OperationTreeParser {
-  private Logger LOG = Logger.getLogger(this.getClass());
-
-  /** Ergebnis-Typ von {@link #checkRuleClosing(String)}. */
-  static private enum RuleClosingType {
-    none,       // Formel wird nicht beendet
-    rule_part,  // Formel wird beendet
-    func_pram   // Formel wird beendet UND glz. ein Funktions-Parameter
-  };
-
-  /** Stellt einen Stack dar, auf den die geoeffneten Klammern gelegt werden.
-   *  Zeichen 0 stellt das oberste Stack-Element dar. */
-  protected StringBuffer openBrackets = null;
-
-  /** Tokenizer auf den Formel-String. Wird beim Starten des Parse-Vorgangs
-   *  erzeugt.
-   *  @see #parse(String)
-   */
-  protected PushbackStringTokenizer tok = null;
-  /** Entaehlt die Delimiter des Tokenizers {@link #tok}. Diese setzen sich
-   *  aus den oeffnenden und schliessenden Klammern zusammen, sowie aus den
-   *  Operatoren. Wird bei der Instanziierung des {@code OperationTreeParser}
-   *  befuellt.
-   *  @see #getOpeningBracketChars()
-   *  @see #getClosingBracketChars()
-   *  @see #getOperatorChars()
-   */
-  protected String delimiter    = null;
-
-  /**
-   * Erzeugt eine neue Instanz des Parsers.
-   */
-  public OperationTreeParser() {
-    delimiter = getOpeningBracketChars() +
-                getClosingBracketChars() +
-                getStringEncapsulationChars() +
-                getParameterSeperatorChars() +
-                getOperatorChars() + "\n";
-  }
-
-  ///////////////////////////////////////////////////////////////////
-  /////////////////   Konfigurations-Methoden   /////////////////////
-  ///////////////////////////////////////////////////////////////////
-  /**
-   * Liefert die Zeichen, die als oeffnende Klammern verwendet werden.
-   * Unterklassen koennen diese Methode ueberschreiben und Zeichen hinzufuegen.
-   * @return <code>"([{"</code>
-   */
-  public String getOpeningBracketChars() {
-    return "([{";
-  }
-
-  /**
-   * Prueft, ob es sich bei einem String um eine oeffnende Klammer handelt.
-   * @param token Zeichenkette
-   * @see #getOpeningBracketChars()
-   */
-  public boolean isOpeningBracket(String token) {
-    return getOpeningBracketChars().contains(token);
-  }
-
-  /**
-   * Liefert die Zeichen, die als schliessende Klammern verwendet werden.
-   * Unterklassen koennen diese Methode ueberschreiben und Zeichen hinzufuegen.
-   * @return <code>")]}"</code>
-   */
-  public String getClosingBracketChars() {
-    return ")]}";
-  }
-
-  /**
-   * Prueft, ob es sich bei einem String um eine schliessende Klammer handelt.
-   * @param token Zeichenkette
-   * @see #getClosingBracketChars()
-   */
-  public boolean isClosingBracket(String token) {
-    return getClosingBracketChars().contains(token);
-  }
-
-  /**
-   * Prueft, ob eine oeffnende und eine schliessende Klammer zueinander
-   * korrespondieren.
-   * Unterklassen muessen diese Methode ueberschreiben und erweitern, wenn
-   * weitere Klammer-Zeichen verwendet werden.
-   * @param openBracket oeffnende Klammer
-   * @param closeBracket schliessende Klammer
-   */
-  public boolean checkCorrespondingBrackets(char openBracket, char closeBracket) {
-    return openBracket == '(' && closeBracket == ')' ||
-           openBracket == '[' && closeBracket == ']' ||
-           openBracket == '{' && closeBracket == '}';
-  }
-
-  /**
-   * Liefert die Zeichen, zwischen denen String-Konstanten gekapselt werden.
-   * Unterklassen koennen diese Methode ueberschreiben und Zeichen hinzufuegen.
-   * @return <code>"'</code>
-   */
-  public String getStringEncapsulationChars() {
-    return "\"'";
-  }
-
-  /**
-   * Prueft, ob es sich bei einem String um ein Zeichenketten-kapselndes
-   * Zeichen handelt.
-   * @param token Zeichenkette
-   * @see #getStringEncapsulationChars()
-   */
-  public boolean isStringEncapsulationChar(String token) {
-    return getStringEncapsulationChars().contains(token);
-  }
-
-  /**
-   * Liefert die Zeichen, die als Trennzeichen zwischen Funktionsparametern
-   * verwendet werden.
-   * Unterklassen koennen diese Methode ueberschreiben und Zeichen hinzufuegen.
-   * @return <code>",;"</code>
-   */
-  public String getParameterSeperatorChars() {
-    return ",;";
-  }
-
-  /**
-   * Prueft, ob es sich bei einem String um eine schliessende Klammer handelt.
-   * @param token Zeichenkette
-   * @see #getClosingBracketChars()
-   */
-  public boolean isParameterSeperator(String token) {
-    return getParameterSeperatorChars().contains(token);
-  }
-
-  /**
-   * Liefert die Zeichen, die als 2-stellige Operatoren verwendet werden.
-   * Unterklassen koennen diese Methode ueberschreiben und Zeichen hinzufuegen.
-   */
-  public String getOperatorChars() {
-    return getAdditionOperatorChars() +
-           getMultiplyOperatorChars() +
-           getCompareOperatorChars() +
-           getBooleanOperatorChars();
-  }
-
-  /**
-   * Prueft, ob es sich bei einem String um einen Operator handelt.
-   * @param token Zeichenkette
-   * @see #getOperatorChars()
-   */
-  public boolean isOperatorChar(String token) {
-//    return getOperatorChars().contains(token);
-    return isAdditionOperator(token)
-        || isBooleanOperator(token)
-        || isCompareOperator(token)
-        || isMultiplyOperator(token);
-  }
-
-
-  /**
-   * Liefert die Zeichen, die als arithmetische Punkt-Operatoren verwendet werden.
-   * Unterklassen koennen diese Methode ueberschreiben und Zeichen hinzufuegen.
-   * @return <code>"/*^"</code>
-   */
-  public String getMultiplyOperatorChars() {
-    return "/*^";
-  }
-
-  /**
-   * Prueft, ob es sich bei einem String um einen Punkt-Operator handelt.
-   * @param token Zeichenkette
-   * @see #getMultiplyOperatorChars()
-   */
-  public boolean isMultiplyOperator(String token) {
-    return getMultiplyOperatorChars().contains(token);
-  }
-
-  /**
-   * Liefert die Zeichen, die als arithmetische Strich-Operatoren verwendet werden.
-   * Unterklassen koennen diese Methode ueberschreiben und Zeichen hinzufuegen.
-   * @return <code>"+-"</code>
-   */
-  public String getAdditionOperatorChars() {
-    return "+-";
-  }
-
-  /**
-   * Prueft, ob es sich bei einem String um einen Strich-Operator handelt.
-   * @param token Zeichenkette
-   * @see #getAdditionOperatorChars()
-   */
-  public boolean isAdditionOperator(String token) {
-    return getAdditionOperatorChars().contains(token);
-  }
-
-  /**
-   * Liefert die Zeichen, die als boolesche Operatoren verwendet werden.
-   * Unterklassen koennen diese Methode ueberschreiben und Zeichen hinzufuegen.
-   * @return {@code "&|!"}
-   */
-  public String getBooleanOperatorChars() {
-    return "&|!";
-  }
-
-  /**
-   * Prueft, ob es sich bei einem String um einen booleschen Operator handelt.
-   * @param token Zeichenkette
-   */
-  public boolean isBooleanOperator(String token) {
-    return getBooleanOperatorChars().contains(token)
-        || token.equalsIgnoreCase("AND")
-        || token.equals("OR");
-  }
-
-  /**
-   * Liefert die Zeichen, die fuer Vergleichsoperatoren verwendet werden.
-   * Unterklassen koennen diese Methode ueberschreiben und Zeichen hinzufuegen.
-   * @return {@code "=<>!"}
-   */
-  public String getCompareOperatorChars() {
-    return "=<>!";
-  }
-
-  /**
-   * Prueft, ob es sich bei einem String um einen Vergleichsoperator handelt.
-   * @param token Zeichenkette
-   */
-  public boolean isCompareOperator(String token) {
-    return token.equals("=") ||
-           token.equals("==") ||
-           token.equals("!=") ||
-           token.equals("<>") ||
-           token.equals(">") ||
-           token.equals(">=") ||
-           token.equals("<") ||
-           token.equals("<=");
-  }
-
-
-
-  /**
-   * Liefert einen Wert, der die Konnektivitaet (Bindung) eines Operators ausdrueckt (je
-   * groesser, desto groesser die Bindung). Punkt-Operatoren haben die
-   * groesste Bindung fuer die Operanden, werden also als erstes ausgewertet.
-   * Darauf folgen die Strich-Operatoren, dann die Vergleichsoperatoren und
-   * am Ende die booleschen Operatoren
-   * @param operator Operator
-   * @return 0, falls kein bekannter Operator uebergeben wird
-   */
-  public int getOperatorConnectivity(String operator) {
-    // Punkt-Operatoren haben den hoechste verbindende Prioritaet
-    if ( isMultiplyOperator(operator) )
-      return 1000;
-    // Strich-Operatoren haben Vorrang vor Vergleichen oder booleschen Operatoren
-    if ( isAdditionOperator(operator) )
-      return 100;
-    // Vergleichs-Operatoren haben Vorrang vor booleschen Operatoren
-    if ( isCompareOperator(operator) )
-      return 10;
-    // boolesche Operatoren haben den geringesten Rang
-    if ( isBooleanOperator(operator) ) {
-      if ( operator.equals("!") )
-        return 3;
-      if ( operator.equals("&") )
-        return 2;
-      if ( operator.equals("|") )
-        return 1;
-    }
-
-    return 0;
-  }
-
-  /**
-   * Liefert den Konnektivitaetswert des am meisten bindenden Operators.
-   * Unterklasse muessen diese Methode u.U. ueberschreiben, wenn durch
-   * Ueberschreiben der Methode {@link #getOperatorConnectivity(String)}
-   * die Prioritaeten der Operatoren veraendert werden.
-   */
-  protected int getMaximumOperatorConnectivity() {
-    return 1000;
-  }
-
-  /**
-   * Liefert die 2-stellige Operatoren, die zwei Operanden aneinander
-   * binden (Punkt-Operatoren).
-   * Unterklassen koennen diese Methode ueberschreiben und Zeichen hinzufuegen.
-   * @return <code>"/*^"</code>
-   * @deprecated wegen booleschen Operatoren muss eine Verbindungs-Prioritaet
-                 verwendet werden; ersetzt durch {@link #getOperatorConnectivity(String)}
-   */
-  public String getConnectingOperatorChars() {
-    return "/*^";
-  }
-
-  /**
-   * Prueft, ob es sich bei einem 2-stelligen Operator um einen verbindenen
-   * Operator handelt (Punkt-Operator).
-   * @param operator 2-stelliger Operator
-   * @see #getConnectingOperatorChars()
-   * @deprecated wegen booleschen Operatoren muss eine Verbindungs-Prioritaet
-                 verwendet werden; ersetzt durch {@link #getOperatorConnectivity(String)}
-   */
-  public boolean isConnectingOperator(String operator) {
-    return getConnectingOperatorChars().contains(operator);
-  }
-
-  ///////////////////////////////////////////////////////////////////
-  ///////////////////   Methoden fuer Parsen  ///////////////////////
-  ///////////////////////////////////////////////////////////////////
-  /**
-   * Erstellt einen Operator-Baum aus einem Formel-String.
-   * @param rule Formel
-   */
-  public OperationTree parse(String rule) {
-    openBrackets = new StringBuffer();
-//    // Probleme, wenn Formel mit einem geklammerten Ausdruck beginnt
-//    // z.B. "(17+7)*2+1" -> *2+1 wird nicht ausgewertet
-//    // Loesung: Gesamten Ausdruck nochmal klammern
-//    rule = "("+rule.trim()+")";
-//    tok  = new PushbackStringTokenizer(rule,delimiter,true);
-//    return new OperationTree( parseRulePart() );
-    tok  = new PushbackStringTokenizer(rule,delimiter,true);
-    try {
-      return new OperationTree( parseRule() );
-    } catch (NoSuchElementException err) {
-      throwParseError( LangUtil.RESOURCE.getString("OperationTree.err.UnexpectedEOR") );
-    } catch (Exception err) {
-      throwParseError( LangUtil.RESOURCE.getString("OperationTree.err.UnexpectedError"), err );
-    }
-    // kann nicht vorkommen!!
-    return null;
-  }
-
-//  /**
-//   * Parst die naechste Teil-Formel aus dem Tokenizer {@link #tok}. Eine (geklammerter)
-//   * Teilformel ist eine durch Strich-Operatoren verbundene Kette von
-//   * {@linkplain #parseOperand() Operanden}.
-//   */
-//  protected final BinaryTreeNode parseRulePart() {
-//    BinaryTreeNode rulePart    = null;
-//    BinaryTreeNode nextOperand = null;
-//    String         operator    = null;
-//
-//    // Ersten (linken) Operand parsen
-//    String token = nextNonWSToken();
-//    // oeffnende Klammer
-//    if ( isOpeningBracket(token) )
-//      openBrackets.insert(0,token);
-//    else
-//      tok.pushback();
-//
-//    rulePart = parseOperand();
-//    while ( tok.hasMoreTokens() ) {
-//      // Operator parsen (kann nur ein Strich- oder Bool-Operator sein!)
-//      operator = nextNonWSToken();
-//
-//      // Sonderfall: schliessende Klammer
-//      // -> Klammerung ueberpruefen und Teil-Formel beenden
-//      if ( isClosingBracket(operator) ) {
-//        if ( !checkCorrespondingBrackets(openBrackets.charAt(0),operator.charAt(0)) )
-//          throwParseError("Bracket '" + operator + "' can not close '" + openBrackets.charAt(0) + "'");
-//        openBrackets.deleteCharAt(0);
-//        return rulePart;
-//      }
-//
-//      // Pruefen, ob es wirklich ein Operator ist
-//      if ( !isOperatorChar(operator) )
-//        throwParseError("Illegal operator '" + operator + "'");
-//
-//      // Sonderfall: boolesche Operatoren u.U. 2-stellig (<=, >=, !=, <>, ==)
-//      String nToken = nextNonWSToken();
-//      if ( operator.equals("<") && nToken.equals("=") ||
-//           operator.equals(">") && nToken.equals("=") ||
-//           operator.equals("=") && nToken.equals("=") ||
-//           operator.equals("!") && nToken.equals("=") ||
-//           operator.equals("<") && nToken.equals(">") )
-//        operator += nToken;
-//      else
-//        tok.pushback();
-//
-//      // Naechsten Operand parsen
-//      nextOperand = parseOperand();
-//
-//      // Teil zusammensetzen
-//      rulePart = new OperationTree.OperatorNode(operator,rulePart,nextOperand);
-//    }
-//    // keine Token mehr, aber noch offene Klammern
-//    if ( openBrackets.length() > 0 )
-//      throwParseError("Bracket"+(openBrackets.length() > 1 ? "s" : "")+" '"+openBrackets.toString()+"' not closed!");
-//    return rulePart;
-//  }
-//
-//  /**
-//   * Parst den naechsten Operand aus dem Tokenizer {@link #tok}. Ein Operand ist eine
-//   * durch Punkt-Operatoren verbundene Kette von {@linkplain #parseLiteral() Literalen}
-//   * und geklammerten {@linkplain #parseRulePart() Teil-Formeln}.<br>
-//   */
-//  protected final BinaryTreeNode parseOperand() {
-//    BinaryTreeNode operand = null;
-//    BinaryTreeNode nextLiteral = null;
-//    String operator = null;
-//
-//    // Erstes (linkes) Literal parsen
-//    String token = nextNonWSToken();
-//    // oeffnende Klammer direkt am Anfang
-//    // -> Literal besteht aus kompletter Teilformel
-//    if (isOpeningBracket(token)) {
-//      tok.pushback();
-//      operand = parseRulePart();
-//    } else {
-//      // Sonderfall: Operand startet mit Minus-Zeichen (z.B. '-(1+2)' oder '-abs(-4)')
-//      //             -> folgende
-//      if ( token.equals("-") )
-//        operand = new OperationTree.OperatorNode("*", new OperationTree.ConstantNode(-1.0),  parseOperand());
-//      else {
-//        tok.pushback();
-//        operand = parseLiteral();
-//      }
-//    }
-//    while (tok.hasMoreTokens()) {
-//      // Operator parsen
-//      operator = nextNonWSToken();
-//      // wenn schliessende Klammer oder Strich-/Bool-Operator
-//      // -> Operand beenden
-//      if (isClosingBracket(operator) || !isMultiplyOperator(operator)) {
-//        tok.pushback();
-//        return operand;
-//      }
-//      // Pruefen, ob es wirklich ein Operator ist
-//      if ( !isOperatorChar(operator) )
-//        throwParseError("Illegal operator '" + operator + "'");
-//
-//      // Naechstes Literal
-//      token = nextNonWSToken();
-//      tok.pushback();
-//      // oeffnende Klammer
-//      // -> naechstes Literal ist eine komplette Teilformel
-//      if (isOpeningBracket(token))
-//        nextLiteral = parseRulePart();
-//      else
-//        nextLiteral = parseLiteral();
-//
-//      // Operand zusammensetzen
-//      operand = new OperationTree.OperatorNode(operator, operand, nextLiteral);
-//    }
-//
-//    return operand;
-//  }
-
-  /**
-   * Liesst ein weiteres Zeichen aus dem Tokenizer und fuegt dies gegebenfalls
-   * dem Operator hinzu. Dies ist z.B. bei den Vergleichsoperatoren
-   * <=, >=, ==, != und == notwendig.
-   * @param operator Operator
-   */
-  private String expandOperator(String operator) {
-      // Sonderfall: boolesche Operatoren u.U. 2-stellig (<=, >=, !=, <>, ==)
-      String nToken = nextNonWSToken();
-      if ( operator.equals("<") && nToken.equals("=") ||
-           operator.equals(">") && nToken.equals("=") ||
-           operator.equals("=") && nToken.equals("=") ||
-           operator.equals("!") && nToken.equals("=") ||
-           operator.equals("<") && nToken.equals(">") )
-        operator += nToken;
-      else
-        pushbackWithWSToken();
-      return operator;
-  }
-
-  /**
-   * Prueft, ob der aktuelle Operand oder die Teil-Formel aufrund einer
-   * schliessende Klammer oder einem Parameter-Trennzeichen abgeschlossen
-   * werden muss.
-   * @param token aktuelles Zeichen
-   */
-  private RuleClosingType checkRuleClosing(String token) {
-    // Operand/Teil-Formel wird nur bei schliessender Klammer oder
-    // Parameter-Trennzeichen beendet
-    if ( !isClosingBracket(token) &&
-         !isParameterSeperator(token) )
-      return RuleClosingType.none;
-
-    // aktuelle Klammerung ermitteln
-    if ( openBrackets.length() == 0 )
-        throwParseError( LangUtil.RESOURCE.getString("OperationTree.err.TokenNotExpected",token) );
-    char openBracket = openBrackets.charAt(0);
-
-    // Schliessende Klammer
-    if ( isClosingBracket(token) ) {
-        // Flag, ob Klammer eine Funktion mit Parametern f(.,.,...) beendet.
-        // In diesem Fall liegt die verbleibende Anzahl (0) an Parametern
-        // auf dem Stack
-        boolean funcEnding = (openBracket == '0');
-        if ( funcEnding )
-          // korrespondierende oeffnende Klammer liegt vor Parameter-Wert
-          // auf Stack
-          openBracket = openBrackets.charAt(1);
-
-      // Wenn keine oeffnende Klammer auf Stack liegt (sondern ein Parameter-Zaehler)
-      // kann Klammer nicht schliessen, da noch ein Parameter erwartet wird
-      if ( !isOpeningBracket(String.valueOf(openBracket)) )
-        throwParseError( LangUtil.RESOURCE.getString("OperationTree.err.MoreParamsExpected",openBracket) );
-      if ( !checkCorrespondingBrackets(openBracket,token.charAt(0)) )
-        throwParseError( LangUtil.RESOURCE.getString("OperationTree.err.UnexpectedBracket",token,openBracket) );
-
-      return funcEnding ? RuleClosingType.func_pram : RuleClosingType.rule_part;
-    }
-
-    // Trenner zwischen Funktions-Parametern
-    if ( isParameterSeperator(token) ) {
-      if ( isOpeningBracket(String.valueOf(openBracket)) )
-        throwParseError( LangUtil.RESOURCE.getString("OperationTree.err.TokenNotExpected",token) );
-      return RuleClosingType.func_pram;
-    }
-
-    return RuleClosingType.none;
-  }
-
-  /**
-   * Prueft, ob noch offene Klammern auf dem Stack liegen, obwohl keine
-   * Token mehr zu parsen sind. Ist dies der Fall wird eine Exception
-   * geworfen.
-   */
-  private void checkRemainingBrackets() {
-    // keine Token mehr, aber noch offene Klammern
-    if ( !tok.hasMoreTokens() && openBrackets.length() > 0 )
-      throwParseError( LangUtil.RESOURCE.getString("OperationTree.err.BracketsNotClosed",openBrackets.toString()) );
-  }
-
-  /**
-   * Parst eine komplette Formel, bis zum Ende der Eingabe-Formel oder
-   * einem Parameter-Trenner.
-   */
-  protected final BinaryTreeNode parseRule() {
-    String         operator     = null;
-    BinaryTreeNode rulePart     = null;
-    BinaryTreeNode nextOperand  = null;
-
-    // Ersten Formel-Teil parsen
-    rulePart = parseRulePart();
-
-    while ( tok.hasMoreTokens() ) {
-      // Operator parsen
-      operator = nextNonWSToken();
-
-      // Ende der Formel pruefen, kann eigentlich nur das Ende eines
-      // Funktions-Parameters sein, da schliessende Klammern sonst bereits
-      // entfernt wurden...
-      if ( checkRuleClosing(operator) != RuleClosingType.none ) {
-        pushbackWithWSToken();
-        return rulePart;
-      }
-
-      // Pruefen, ob es wirklich ein Operator ist
-      if ( !isOperatorChar(operator) )
-        throwParseError( LangUtil.RESOURCE.getString("OperationTree.err.IllegalOperator", operator) );
-      // Sonderfall: boolesche Operatoren u.U. 2-stellig (<=, >=, !=, <>, ==)
-      operator = expandOperator(operator);
-
-      // Naechsten Operand parsen
-      nextOperand = parseOperand( getOperatorConnectivity(operator) );
-
-      // Teil zusammensetzen
-      rulePart = new OperationTree.OperatorNode(operator,rulePart,nextOperand);
-    }
-
-    checkRemainingBrackets();
-
-    return rulePart;
-  }
-
-  /**
-   * Parst die naechste Teil-Formel aus dem Tokenizer {@link #tok}. Eine (geklammerter)
-   * Teilformel ist eine durch Strich-Operatoren verbundene Kette von
-   * {@linkplain #parseOperand(int) Operanden}.
-   */
-  protected final BinaryTreeNode parseRulePart() {
-    BinaryTreeNode rulePart    = null;
-    BinaryTreeNode nextOperand = null;
-    String         operator    = null;
-
-    // Ersten (linken) Operand parsen
-    String token = nextNonWSToken();
-    // oeffnende Klammer
-    if ( isOpeningBracket(token) )
-      openBrackets.insert(0,token);
-    else
-      pushbackWithWSToken();
-
-    rulePart = parseOperand( getMaximumOperatorConnectivity() );
-    while ( tok.hasMoreTokens() ) {
-      // Operator parsen
-      operator = nextNonWSToken();
-
-      // schliessende Klammer oder Parameter-Trenner beendet die Teil-Formel
-      RuleClosingType closingType = checkRuleClosing(operator);
-      if ( closingType != RuleClosingType.none ) {
-        // Wenn Teil-Formel beendet wird, dann schliessende Klammer
-        // vom Stack entfernen
-        if ( closingType == RuleClosingType.rule_part )
-          openBrackets.deleteCharAt(0);
-        // Wenn Functions-Parameter beendet wird, dann Token zuruecklegen,
-        // damit Beendigung der Formel (in uebergeordneter Methode)
-        // erkannt wird
-        if ( closingType == RuleClosingType.func_pram )
-          pushbackWithWSToken();
-        // (Teil-)Formel beenden
-        return rulePart;
-      }
-
-      // Pruefen, ob es wirklich ein Operator ist
-      if ( !isOperatorChar(operator) )
-        throwParseError( LangUtil.RESOURCE.getString("OperationTree.err.IllegalOperator", operator) );
-      // Sonderfall: boolesche Operatoren u.U. 2-stellig (<=, >=, !=, <>, ==)
-      operator = expandOperator(operator);
-
-      // Naechsten Operand parsen
-      nextOperand = parseOperand( getOperatorConnectivity(operator) );
-
-      // Teil zusammensetzen
-      rulePart = new OperationTree.OperatorNode(operator,rulePart,nextOperand);
-    }
-
-    checkRemainingBrackets();
-
-    return rulePart;
-  }
-
-  /**
-   * Parst den naechsten Operand aus dem Tokenizer {@link #tok}. Ein Operand ist eine
-   * durch Operatoren gleicher Konnektivitaet verbundene Kette von
-   * {@linkplain #parseLiteral() Literalen} und geklammerten
-   * {@linkplain #parseRulePart() Teil-Formeln}.<br>
-   * @param minOperandConn minimale Konnektivitaet fuer den Operanden (bei einem
-   *                       Operator mit kleinerer Konnektivitaet wird der
-   *                       Operand beendet)
-   */
-  protected final BinaryTreeNode parseOperand(int minOperatorConn) {
-    BinaryTreeNode operand = null;
-    BinaryTreeNode nextLiteral = null;
-    String operator = null;
-    int lastOperatorConn = this.getMaximumOperatorConnectivity();
-
-    // Erstes (linkes) Literal parsen
-    String token = nextNonWSToken();
-    // oeffnende Klammer direkt am Anfang
-    // -> Literal besteht aus kompletter Teilformel
-    if (isOpeningBracket(token)) {
-      pushbackWithWSToken();
-      operand = parseRulePart();
-    } else {
-      // Sonderfall: Operand startet mit Minus-Zeichen (z.B. '-(1+2)' oder '-abs(-4)')
-      //             -> folgende
-      if ( token.equals("-") )
-        operand = new OperationTree.OperatorNode("*", new OperationTree.ConstantNode(-1.0),  parseOperand(getOperatorConnectivity("*")));
-      else {
-        pushbackWithWSToken();
-        operand = parseLiteral();
-      }
-    }
-    while (tok.hasMoreTokens()) {
-      // Operator parsen
-      operator = nextNonWSToken();
-      // schliessende Klammer oder Parameter-Trenner beendet den Operand
-      if ( checkRuleClosing(operator) != RuleClosingType.none) {
-        pushbackWithWSToken();
-        return operand;
-      }
-
-      // Pruefen, ob es wirklich ein Operator ist
-      if ( !isOperatorChar(operator) )
-        throwParseError( LangUtil.RESOURCE.getString("OperationTree.err.IllegalOperator", operator) );
-      // Sonderfall: boolesche Operatoren u.U. 2-stellig (<=, >=, !=, <>, ==)
-      operator = expandOperator(operator);
-
-      int operatorConn = getOperatorConnectivity(operator);
-      // Operator mit geringerer Konnektivitaet beendet den Operand
-      if ( operatorConn < minOperatorConn ) {
-        for (int i=0; i<operator.length(); i++)
-        pushbackWithWSToken();
-        return operand;
-      }
-
-//      // Operator mit hoeherer Konnektivitaet erzeugt einen neuen Operand
-//      // Ausnahme: erste Operation im Operand ('operand' hat noch keine Kinder)!
-//      if ( operatorConn > minOperandConn && !operand.isLeaf() ) {
-
-      // Operator mit hoeherer Konnektivitaet, als der letzte Operator, erzeugt
-      // einen neuen Operand
-      if ( operatorConn > lastOperatorConn ) {
-        BinaryTreeNode operandHigher = parseOperand(operatorConn);
-        // Das letzte Literal ist der erste Operand von 'operandHigher'
-        operand.setRightChild(
-          new OperationTree.OperatorNode(
-                  operator,
-                  operand.getRightChild(),
-                  operandHigher
-          )
-        );
-        // mit naechstem Operator fortfahren
-        lastOperatorConn = operatorConn;
-        continue;
-      }
-
-      // Naechstes Literal
-      token = nextNonWSToken();
-      pushbackWithWSToken();
-      // oeffnende Klammer
-      // -> naechstes Literal ist eine komplette Teilformel
-      if (isOpeningBracket(token))
-        nextLiteral = parseRulePart();
-      else
-        nextLiteral = parseLiteral();
-
-      // Operand zusammensetzen
-      operand = new OperationTree.OperatorNode(operator, operand, nextLiteral);
-
-      lastOperatorConn = operatorConn;
-    }
-
-    return operand;
-  }
-
-
-
-  /**
-   * Parst das naechste Literal aus dem Tokenizer {@link #tok}. Ein Literal ist eine numerische
-   * Konstante, ein Alias oder ein 1-stelliger Operator auf einer geklammerten
-   * {@linkplain #parseRulePart() Teil-Formel}. Diese Methode unterstuetzt
-   * <ul>
-   *   <li>als 1-stellige Operatoren
-   *      <ul>
-   *         <li>Betrag: {@code "abs(.)"}</li>
-   *         <li>Wurzel: {@code "sqr(.)"} oder {@code "sqrt(.)"}</li>
-   *         <li>Runden: {@code "rnd(.)"} oder {@code "round(.)"}</li>
-   *         <li>Abschneiden: {@code "int(.)"} oder {@code "trunc(.)"}</li>
-   *         <li>boolesches NICHT: {@code "!(.)"} oder {@code "not(.)"}</li>
-   *         <li>Test auf "Not a Number" (NaN): {@code "isNaN(.)"}</li>
-   *         <li>Sinus: {@code "sin(.)"}</li>
-   *         <li>Cosinus: {@code "cos(.)"}</li>
-   *         <li>Tangens: {@code "tan(.)"}</li>
-   *         <li>Arcus-Sinus: {@code "arcsin(.)"} oder {@code "asin(.)"}</li>
-   *         <li>Arcus-Cosinus: {@code "arccos(.)"} oder {@code "acos(.)"}</li>
-   *         <li>Arcus-Tangens: {@code "arctan(.)"} oder {@code "atan(.)"}</li>
-   *         <li>Exponentialfunktion: {@code "exp(.)"}</li>
-   *         <li>Logarithmus zur Basis e: {@code "ln(.)"}</li>
-   *         <li>Logarithmus zur Basis 10: {@code "log(.)"}</li>
-   *         <li>Umwandlung Zahl-zu-String: {@code "str(.)"}</li>
-   *         <li>Umwandlung String-zu-Zahl: {@code "val(.)"}</li>
-   *         <li>Laenge eines Strings: {@code "len(.)"}</li>
-   *         <li>Umwandlung in Gross-Buchstaben: {@code "toupper(.)"}</li>
-   *         <li>Umwandlung in Klein-Buchstaben: {@code "tolower(.)"}</li>
-   *       </ul></li>
-   *   <li>als Alias (0-stellige Operatoren)
-   *       <ul>
-   *         <li>Zufallszahl zwischen 0 und 1: {@code "rand"} oder {@code "random"}</li>
-   *         <li>"Not a number" (NaN): {@code "NaN"}</li>
-   *       </ul></li>
-   *   <li>als Sonderfaelle
-   *       <ul>
-   *         <li>IF .. THEN .. ELSE ..: {@code "ITE(.,.,.)"}</li>
-   *       </ul></li>
-   * </ul>
-   * <b>Sub-Klassen muessen diese Methode erweitern, wenn z.B. (alphanumerische)
-   * Variablen oder zusaetzliche 1-stellige Operatoren beruecksichtigt werden
-   * sollen!!</b>
-   */
-  protected BinaryTreeNode parseLiteral() {
-    String token = nextNonWSToken().toLowerCase();
-
-    // Sonderfall: in Anfuehrungsstriche gekapselte String-Konstante
-    if ( isStringEncapsulationChar(token) ) {
-      // Token (Anfuehrungsstrichen) erweitern um alles, bis zum naechsten
-      // Anfuehrungsstrich gleicher Art
-      String encChar = token;
-      // Bemerkung: tok.nextToken(encChar) funktioniert nicht so richtig,
-      //            wohl wegen PushBack-Funktionalitaet. Zudem aendert
-      //            dieser Aufruf die Delimiter dauerhaft!
-      do {
-        token += tok.nextToken();
-      } while (!token.endsWith(encChar));
-    }
-
-
-    // Betrag, Wurzel, Runden
-    if ( token.equals("abs") ||
-         token.equals("sqr") || token.equals("sqrt") ||
-         token.equals("rnd") || token.equals("round") ||
-         token.equals("int") || token.equals("trunc") ||
-         token.equals("!")   || token.equals("not") ||
-         token.equals("isnan") ||
-         token.equals("sin") ||
-         token.equals("cos") ||
-         token.equals("tan") ||
-         token.equals("arcsin") || token.equals("asin") ||
-         token.equals("arccos") || token.equals("acos") ||
-         token.equals("arctan") || token.equals("atan") ||
-         token.equals("exp") ||
-         token.equals("log") ||
-         token.equals("ln") ||
-         token.equals("str")     || token.equals("val") ||
-         token.equals("len") ||
-         token.equals("toupper") || token.equals("tolower") ) {
-      return new OperationTree.UnaryOperatorNode(token, parseRulePart());
-    }
-    // Zufallszahl oder NaN-Konstante
-    if ( token.equals("rand") || token.equals("random") ||
-         token.equals("nan")  || token.equals("curr_millis")) {
-      return new OperationTree.ConstantAliasNode(token);
-    }
-    // ITE(a,b,c) = IF a THEN b ELSE c
-    if ( token.equals("ite") ) {
-        // Parameter fuer ITE parsen
-        BinaryTreeNode[] iteParam = parseFunctionParameters("ITE",3);
-        // Baum fuer ITE
-        return new OperationTree.ITENode(token,iteParam[0],iteParam[1],iteParam[2]);
-    }
-
-    // REGEX(string,regexpr) = Regular Expression
-    if ( token.equals("regex") ) {
-      // Parameter fuer REGEX parsen
-      BinaryTreeNode[] regexParam = parseFunctionParameters("REGEX",2);
-      // Baum fuer REGEX
-      return new OperationTree.OperatorNode(token,regexParam[0],regexParam[1]);
-    }
-
-    // SPLIT(string,regexpr) = String-Split
-    if ( token.equals("split") ) {
-      // Parameter fuer SPLIT parsen
-      BinaryTreeNode[] splitParam = parseFunctionParameters("SPLIT",3);
-      // Baum fuer SPLIT
-      return new OperationTree.MultiParamOperatorNode(token,null,splitParam);
-    }
-
-    // SUBSTR(string,startPos_inkl,endPos_exkl) = Teil-String
-    if ( token.equals("substr") ) {
-      // Parameter fuer SUBSTR parsen
-      BinaryTreeNode[] substrParam = parseFunctionParameters("SUBSTR",3);
-      // Baum fuer SPLIT
-      return new OperationTree.MultiParamOperatorNode(token,null,substrParam);
-    }
-
-    // REPLALL(string,pattern,replacement) = String-Ersetzung
-    if ( token.equals("replall") ) {
-      // Parameter fuer REPLALL parsen
-      BinaryTreeNode[] substrParam = parseFunctionParameters("REPLALL",3);
-      // Baum fuer REPLALL
-      return new OperationTree.MultiParamOperatorNode(token,null,substrParam);
-    }
-
-    // sonst: Konstante
-    return new OperationTree.ConstantNode(getConstantFromString(token));
-  }
-
-  /**
-   * Parst die Funktions-Parameter fuer eine Funktion F(.,.,.,.).
-   * @param operator Name des Operators (nur fuer Exception-Beschreibung)
-   * @param paramCount Anzahl der erwarteten Parameter
-   */
-  private BinaryTreeNode[] parseFunctionParameters(String operator, int paramCount) {
-    BinaryTreeNode[] paramNode = new BinaryTreeNode[paramCount];
-
-    // naechstes Token muss eine oeffnende Klammer sein!
-    String token = nextNonWSToken();
-    if ( !token.equals("(") )
-    throwParseError( LangUtil.RESOURCE.getString("OperationTree.err.IllegalOperatorSyntax", operator, token) );
-    openBrackets.insert(0,"(");
-
-    openBrackets.insert(0, String.valueOf(paramCount-1)); // noch X weitere Parameter (Trenner) erwartet
-    // parCount-1 Parameter parsen
-    for (int i=0; i<paramCount-1; i++) {
-      // Parameter fuer ITE lesen
-      paramNode[i] = parseRule();
-      if ( !isParameterSeperator( tok.nextToken() ) ) // Seperator entfernen
-        throwParseError( LangUtil.RESOURCE.getString("OperationTree.err.ParamSepExpected") );
-      openBrackets.replace(0, 1, String.valueOf(paramCount-(i+2))); // noch X-1 weiterer Parameter (Trenner) erwartet
-    }
-    // den letzten Parameter parsen
-    paramNode[paramNode.length-1] = parseRule();
-    // Funktion-schliessende Klammer entfernen (Pruefung auf Konsistenz mit
-    // oeffnender Klammer erfolgte bereits in checkRuleClosing(.)
-    tok.nextToken();
-    // Parameter-Zaehler von Stack entfernen
-    openBrackets.deleteCharAt(0);
-    // Funktion-oeffnende Klammer von Stack entfernen
-    openBrackets.deleteCharAt(0);
-
-    return paramNode;
-  }
-
-  ///////////////////////////////////////////////////////////////////
-  //////////////////////   Hilfsmethoden   //////////////////////////
-  ///////////////////////////////////////////////////////////////////
-  /**
-   * Wirft eine {@link IllegalArgumentException} mit der angegebenen Fehlermeldung.
-   * Als zusaetzlicher Hinweis wird das Formel-Praefix ausgegeben nach dem
-   * der Fehler aufgetreten ist.
-   * @param mess Fehler-Meldung
-   */
-  protected void throwParseError(String mess) {
-    throwParseError(mess,null);
-  }
-
-  /**
-   * Wirft eine {@link IllegalArgumentException} mit der angegebenen Fehlermeldung.
-   * Als zusaetzlicher Hinweis wird das Formel-Praefix ausgegeben nach dem
-   * der Fehler aufgetreten ist.
-   * @param mess Fehler-Meldung
-   * @param err  verursachender Fehler
-   */
-  protected void throwParseError(String mess, Throwable err) {
-    String errorPos = tok.getReadTokens();
-//    // Die Klammer entfernen, die am Anfang kuenstlich eingefuegt wurde
-//    errorPos = errorPos.substring(1);
-    if ( err != null )
-      throw new IllegalArgumentException( LangUtil.RESOURCE.getString("OperationTree.err.ParseErrorMess", errorPos, mess), err );
-    else
-      throw new IllegalArgumentException( LangUtil.RESOURCE.getString("OperationTree.err.ParseErrorMess", errorPos, mess) );
-  }
-
-  /**
-   * Liefert einen Double- oder String-Wert aus einem String. String-Konstanten
-   * muessen in " oder ' gekapselt sein, um als solche interpretiert zu werden.
-   * Die Wildcards {@code TRUE} und {@code FALSE} werden in 1 bzw. 0 umgewandelt.
-   * @param token umzuwandelnde Zeichenkette
-   * @exception IllegalArgumentException falls die Umwandlung nicht vorgenommen
-   *            werden kann
-   */
-  protected Object getConstantFromString(String token) {
-    // Sonderfall: String-Konstante in Anfuehrungsstrichen
-    if ( token.length()>0 && isStringEncapsulationChar(token.substring(0,1)) )
-      return token.substring(1, token.length()-1);
-    // Sonderfall: TRUE/FALSE als Wildcards fuer 1/0
-    if ( token.equalsIgnoreCase("TRUE") )
-      return 1;
-    if ( token.equalsIgnoreCase("FALSE") )
-      return 0;
-    // Sonst eine numerische Konstante
-    return getDoubleFromString(token);
-  }
-
-  /**
-   * Liefert einen Integer-Wert aus einem String.
-   * @param token umzuwandelnde Zeichenkette
-   * @exception IllegalArgumentException falls die Umwandlung nicht vorgenommen
-   *            werden kann
-   */
-  protected int getIntFromString(String token) {
-    token = token.trim();
-    try {
-      return Integer.parseInt(token);
-    }
-    catch (Exception err) {
-      throwParseError( LangUtil.RESOURCE.getString(
-                                 "OperationTree.err.IllegalCharacter",
-                                 token,
-                                 LangUtil.RESOURCE.getString("OperationTree.Integer")
-      ));
-    }
-    return 0;
-  }
-
-  /**
-   * Liefert einen Double-Wert aus einem String.
-   * @param token umzuwandelnde Zeichenkette
-   * @exception IllegalArgumentException falls die Umwandlung nicht vorgenommen
-   *            werden kann
-   */
-  protected double getDoubleFromString(String token) {
-    token = token.trim();
-    // Sonderfall: Bei alleinstehender negativer Konstante ist im Token nur
-    //             das Minus-Zeichen enthalten! Zahl-Token muss angehaengt werden.
-    if ( token.equals("-") )
-      token += nextNonWSToken();
-
-    try {
-      return Double.parseDouble(token);
-    }
-    catch (Exception err) {
-      throwParseError( LangUtil.RESOURCE.getString(
-                               "OperationTree.err.IllegalCharacter",
-                               token,
-                               LangUtil.RESOURCE.getString("OperationTree.Number")
-      ));
-    }
-    return 0;
-  }
-
-  /**
-   * Liefert das naechste Token aus dem Tokenizer, das nicht ein White-Space
-   * ist.
-   */
-  protected String nextNonWSToken() {
-    String token = null;
-    while ( (token = tok.nextToken()).trim().equals("") );
-    return token.trim();
-  }
-
-  /**
-   * Legt solange Token zurueck auf den Tokenizer, bis das zurueckgelegte
-   * Token <b>kein</b> White-Space ist.
-   */
-  protected void pushbackWithWSToken() {
-    while ( tok.pushback().trim().equals("") );
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.lang.tree;
+
+import java.util.NoSuchElementException;
+
+import org.apache.log4j.Logger;
+
+import schmitzm.lang.LangUtil;
+import schmitzm.lang.PushbackStringTokenizer;
+import schmitzm.lang.tree.OperationTree.ConstantAliasNode;
+import schmitzm.lang.tree.OperationTree.ConstantNode;
+import schmitzm.lang.tree.OperationTree.ITENode;
+import schmitzm.lang.tree.OperationTree.MultiParamOperatorNode;
+import schmitzm.lang.tree.OperationTree.OperatorNode;
+import schmitzm.lang.tree.OperationTree.UnaryOperatorNode;
+
+/**
+ * Diese Klasse stellt einen Parser fuer einen {@linkplain OperationTree Operator-Baum}
+ * dar. Dieser erstellt einen {@linkplain OperationTree Operator-Baum} aus einem
+ * Formel-String, der folgende Teilen bestehen darf:
+ * <ul>
+ *   <li>konstante numerische Werte: {@link ConstantNode}</li>
+ *       <ul>
+ *           <li>Zahlen im {@code double}-Bereich</li>
+ *           <li>{@code rand} oder {@code random} als Alias fuer eine Zufallszahl
+ *                zwischen 0 und 1: {@link ConstantAliasNode}</li>
+ *           <li>"Not a number" (NaN): {@code "NaN"}</li>
+ *           <li>boolesches WAHR (1): {@code "TRUE"}</li>
+ *           <li>boolesches FALSCH (0): {@code "FALSE"}</li>
+ *           <li>Aktuelle Zeit in ms ({@link System#currentTimeMillis()}): {@code "CURR_MILLIS"}</li>
+ *       </ul></li>
+ *   <li>konstante String Werte: {@link ConstantNode}</li>
+ *       <ul>
+ *           <li>Zeichenketten, die durch " oder ' eingeleitet und abgeschlossen
+ *               werden</li>
+ *       </ul></li>
+ *   <li>den 2-stelligen arithmetischen Operatoren: {@link OperatorNode}
+ *       <ul>
+ *          <li>Addition: {@code "+"}</li>
+ *          <li>Subtraktion: {@code "-"}</li>
+ *          <li>Multiplikation: {@code "*"}</li>
+ *          <li>Division: {@code "/"}</li>
+ *          <li>Potenzbildung: {@code "^"}</li>
+ *        </ul></li>
+ *   <li>den 2-stelligen booleschen Operatoren: {@link OperatorNode}
+ *       <ul>
+ *          <li>boolesches UND: {@code "&"}</li>
+ *          <li>boolesches ODER: {@code "|"}</li>
+ *          <li>Gleich: {@code "="} oder {@code "=="}</li>
+ *          <li>Ungleich: {@code "!="} oder {@code "<>"}</li>
+ *          <li>Kleiner als: {@code "<"}</li>
+ *          <li>Groesser als: {@code ">"}</li>
+ *          <li>Kleiner gleich: {@code "<="}</li>
+ *          <li>Groesser gleich: {@code ">="}</li>
+ *        </ul></li>
+ *   <li>den 2-stelligen Zeichenketten-Operatoren: {@link OperatorNode}
+ *       <ul>
+ *          <li>String-Konkatenation: {@code "+"}</li>
+ *          <li>Test auf regulaeren Ausdruck: {@code "regex(expression,regular expr)"}</li>
+ *          <li>n-tes Ergebnis eines {@linkplain String#split(String) String-Splits} ueber regulaeren Ausdruck: {@code "split(expression,regular expr,n)"}</li>
+ *       </ul></li>
+ *   <li>den mehr-stelligen Zeichenketten-Operatoren: {@link MultiParamOperatorNode}
+ *       <ul>
+ *          <li>Teil-String: {@code "substr(expression,startPos_inkl,endPos_exkl)"}</li>
+ *          <li>String-Ersetzung: {@code "replAll(expression,pattern,replacement)"}</li>
+ *       </ul></li>
+ *   <li>die 1-stelligen Operatoren: {@link UnaryOperatorNode}
+ *       <ul>
+ *          <li>Betrag: {@code "abs(.)"}</li>
+ *          <li>Wurzel: {@code "sqr(.)"} oder {@code "sqrt(.)"}</li>
+ *          <li>Runden: {@code "rnd(.)"} oder {@code "round(.)"}</li>
+ *          <li>Abschneiden: {@code "int(.)"} oder {@code "trunc(.)"}</li>
+ *          <li>Test auf "Not a Number" (NaN): {@code "isNaN(.)"}</li>
+ *          <li>Sinus: {@code "sin(.)"}</li>
+ *          <li>Cosinus: {@code "cos(.)"}</li>
+ *          <li>Tangens: {@code "tan(.)"}</li>
+ *          <li>Arcus-Sinus: {@code "arcsin(.)"} oder {@code "asin(.)"}</li>
+ *          <li>Arcus-Cosinus: {@code "arccos(.)"} oder {@code "acos(.)"}</li>
+ *          <li>Arcus-Tangens: {@code "arctan(.)"} oder {@code "atan(.)"}</li>
+ *          <li>Exponentialfunktion: {@code "exp(.)"}</li>
+ *          <li>Logarithmus zur Basis e: {@code "ln(.)"}</li>
+ *          <li>Logarithmus zur Basis 10: {@code "log(.)"}</li>
+ *        </ul></li>
+ *   <li>den 1-stelligen booleschen Operatoren: {@link UnaryOperatorNode}
+ *       <ul>
+ *          <li>boolesches NICHT: {@code "!(.)"}</li>
+ *        </ul></li>
+ *   <li>den 1-stelligen String-Operatoren: {@link UnaryOperatorNode}
+ *       <ul>
+ *          <li>Umwandlung Zahl-zu-String: {@code "str(.)"}</li>
+ *          <li>Umwandlung String-zu-Zahl: {@code "val(.)"}</li>
+ *          <li>Umwandlung in Gross-Buchstaben: {@code "toupper(.)"}</li>
+ *          <li>Umwandlung in Klein-Buchstaben: {@code "tolower(.)"}</li>
+ *          <li>Laenge eines Strings: {@code "len(.)"}</li>
+ *        </ul></li>
+ *   <li>dem 3-stelligen Operator {@code ITE(.,.,.)}: {@link ITENode}<br>
+ *       Der ITE-Operator drueckt eine Bedingung "IF .. THEN .. ELSE .." aus.</li>
+ * </ul>
+ * <br>
+ * Damit boolesche Operatoren und arithmetische Ausdruecke kombiniert
+ * werden koennen, werden die Operanden und das Ergebis einer booleschen
+ * Operation nicht als TRUE oder FALSE, sondern numerisch codiert:<br>
+ * <b>Operanden:</b> {@code op > 0} entspricht TRUE; {@code op = 0} entspricht FALSE.<br>
+ * <b>Ergebnis:</b> TRUE wird als 1 codiert; FALSE wird als 0 codiert.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class OperationTreeParser {
+  private Logger LOG = Logger.getLogger(this.getClass());
+
+  /** Ergebnis-Typ von {@link #checkRuleClosing(String)}. */
+  static private enum RuleClosingType {
+    none,       // Formel wird nicht beendet
+    rule_part,  // Formel wird beendet
+    func_pram   // Formel wird beendet UND glz. ein Funktions-Parameter
+  };
+
+  /** Stellt einen Stack dar, auf den die geoeffneten Klammern gelegt werden.
+   *  Zeichen 0 stellt das oberste Stack-Element dar. */
+  protected StringBuffer openBrackets = null;
+
+  /** Tokenizer auf den Formel-String. Wird beim Starten des Parse-Vorgangs
+   *  erzeugt.
+   *  @see #parse(String)
+   */
+  protected PushbackStringTokenizer tok = null;
+  /** Entaehlt die Delimiter des Tokenizers {@link #tok}. Diese setzen sich
+   *  aus den oeffnenden und schliessenden Klammern zusammen, sowie aus den
+   *  Operatoren. Wird bei der Instanziierung des {@code OperationTreeParser}
+   *  befuellt.
+   *  @see #getOpeningBracketChars()
+   *  @see #getClosingBracketChars()
+   *  @see #getOperatorChars()
+   */
+  protected String delimiter    = null;
+
+  /**
+   * Erzeugt eine neue Instanz des Parsers.
+   */
+  public OperationTreeParser() {
+    delimiter = getOpeningBracketChars() +
+                getClosingBracketChars() +
+                getStringEncapsulationChars() +
+                getParameterSeperatorChars() +
+                getOperatorChars() + "\n";
+  }
+
+  ///////////////////////////////////////////////////////////////////
+  /////////////////   Konfigurations-Methoden   /////////////////////
+  ///////////////////////////////////////////////////////////////////
+  /**
+   * Liefert die Zeichen, die als oeffnende Klammern verwendet werden.
+   * Unterklassen koennen diese Methode ueberschreiben und Zeichen hinzufuegen.
+   * @return <code>"([{"</code>
+   */
+  public String getOpeningBracketChars() {
+    return "([{";
+  }
+
+  /**
+   * Prueft, ob es sich bei einem String um eine oeffnende Klammer handelt.
+   * @param token Zeichenkette
+   * @see #getOpeningBracketChars()
+   */
+  public boolean isOpeningBracket(String token) {
+    return getOpeningBracketChars().contains(token);
+  }
+
+  /**
+   * Liefert die Zeichen, die als schliessende Klammern verwendet werden.
+   * Unterklassen koennen diese Methode ueberschreiben und Zeichen hinzufuegen.
+   * @return <code>")]}"</code>
+   */
+  public String getClosingBracketChars() {
+    return ")]}";
+  }
+
+  /**
+   * Prueft, ob es sich bei einem String um eine schliessende Klammer handelt.
+   * @param token Zeichenkette
+   * @see #getClosingBracketChars()
+   */
+  public boolean isClosingBracket(String token) {
+    return getClosingBracketChars().contains(token);
+  }
+
+  /**
+   * Prueft, ob eine oeffnende und eine schliessende Klammer zueinander
+   * korrespondieren.
+   * Unterklassen muessen diese Methode ueberschreiben und erweitern, wenn
+   * weitere Klammer-Zeichen verwendet werden.
+   * @param openBracket oeffnende Klammer
+   * @param closeBracket schliessende Klammer
+   */
+  public boolean checkCorrespondingBrackets(char openBracket, char closeBracket) {
+    return openBracket == '(' && closeBracket == ')' ||
+           openBracket == '[' && closeBracket == ']' ||
+           openBracket == '{' && closeBracket == '}';
+  }
+
+  /**
+   * Liefert die Zeichen, zwischen denen String-Konstanten gekapselt werden.
+   * Unterklassen koennen diese Methode ueberschreiben und Zeichen hinzufuegen.
+   * @return <code>"'</code>
+   */
+  public String getStringEncapsulationChars() {
+    return "\"'";
+  }
+
+  /**
+   * Prueft, ob es sich bei einem String um ein Zeichenketten-kapselndes
+   * Zeichen handelt.
+   * @param token Zeichenkette
+   * @see #getStringEncapsulationChars()
+   */
+  public boolean isStringEncapsulationChar(String token) {
+    return getStringEncapsulationChars().contains(token);
+  }
+
+  /**
+   * Liefert die Zeichen, die als Trennzeichen zwischen Funktionsparametern
+   * verwendet werden.
+   * Unterklassen koennen diese Methode ueberschreiben und Zeichen hinzufuegen.
+   * @return <code>",;"</code>
+   */
+  public String getParameterSeperatorChars() {
+    return ",;";
+  }
+
+  /**
+   * Prueft, ob es sich bei einem String um eine schliessende Klammer handelt.
+   * @param token Zeichenkette
+   * @see #getClosingBracketChars()
+   */
+  public boolean isParameterSeperator(String token) {
+    return getParameterSeperatorChars().contains(token);
+  }
+
+  /**
+   * Liefert die Zeichen, die als 2-stellige Operatoren verwendet werden.
+   * Unterklassen koennen diese Methode ueberschreiben und Zeichen hinzufuegen.
+   */
+  public String getOperatorChars() {
+    return getAdditionOperatorChars() +
+           getMultiplyOperatorChars() +
+           getCompareOperatorChars() +
+           getBooleanOperatorChars();
+  }
+
+  /**
+   * Prueft, ob es sich bei einem String um einen Operator handelt.
+   * @param token Zeichenkette
+   * @see #getOperatorChars()
+   */
+  public boolean isOperatorChar(String token) {
+//    return getOperatorChars().contains(token);
+    return isAdditionOperator(token)
+        || isBooleanOperator(token)
+        || isCompareOperator(token)
+        || isMultiplyOperator(token);
+  }
+
+
+  /**
+   * Liefert die Zeichen, die als arithmetische Punkt-Operatoren verwendet werden.
+   * Unterklassen koennen diese Methode ueberschreiben und Zeichen hinzufuegen.
+   * @return <code>"/*^"</code>
+   */
+  public String getMultiplyOperatorChars() {
+    return "/*^";
+  }
+
+  /**
+   * Prueft, ob es sich bei einem String um einen Punkt-Operator handelt.
+   * @param token Zeichenkette
+   * @see #getMultiplyOperatorChars()
+   */
+  public boolean isMultiplyOperator(String token) {
+    return getMultiplyOperatorChars().contains(token);
+  }
+
+  /**
+   * Liefert die Zeichen, die als arithmetische Strich-Operatoren verwendet werden.
+   * Unterklassen koennen diese Methode ueberschreiben und Zeichen hinzufuegen.
+   * @return <code>"+-"</code>
+   */
+  public String getAdditionOperatorChars() {
+    return "+-";
+  }
+
+  /**
+   * Prueft, ob es sich bei einem String um einen Strich-Operator handelt.
+   * @param token Zeichenkette
+   * @see #getAdditionOperatorChars()
+   */
+  public boolean isAdditionOperator(String token) {
+    return getAdditionOperatorChars().contains(token);
+  }
+
+  /**
+   * Liefert die Zeichen, die als boolesche Operatoren verwendet werden.
+   * Unterklassen koennen diese Methode ueberschreiben und Zeichen hinzufuegen.
+   * @return {@code "&|!"}
+   */
+  public String getBooleanOperatorChars() {
+    return "&|!";
+  }
+
+  /**
+   * Prueft, ob es sich bei einem String um einen booleschen Operator handelt.
+   * @param token Zeichenkette
+   */
+  public boolean isBooleanOperator(String token) {
+    return getBooleanOperatorChars().contains(token)
+        || token.equalsIgnoreCase("AND")
+        || token.equals("OR");
+  }
+
+  /**
+   * Liefert die Zeichen, die fuer Vergleichsoperatoren verwendet werden.
+   * Unterklassen koennen diese Methode ueberschreiben und Zeichen hinzufuegen.
+   * @return {@code "=<>!"}
+   */
+  public String getCompareOperatorChars() {
+    return "=<>!";
+  }
+
+  /**
+   * Prueft, ob es sich bei einem String um einen Vergleichsoperator handelt.
+   * @param token Zeichenkette
+   */
+  public boolean isCompareOperator(String token) {
+    return token.equals("=") ||
+           token.equals("==") ||
+           token.equals("!=") ||
+           token.equals("<>") ||
+           token.equals(">") ||
+           token.equals(">=") ||
+           token.equals("<") ||
+           token.equals("<=");
+  }
+
+
+
+  /**
+   * Liefert einen Wert, der die Konnektivitaet (Bindung) eines Operators ausdrueckt (je
+   * groesser, desto groesser die Bindung). Punkt-Operatoren haben die
+   * groesste Bindung fuer die Operanden, werden also als erstes ausgewertet.
+   * Darauf folgen die Strich-Operatoren, dann die Vergleichsoperatoren und
+   * am Ende die booleschen Operatoren
+   * @param operator Operator
+   * @return 0, falls kein bekannter Operator uebergeben wird
+   */
+  public int getOperatorConnectivity(String operator) {
+    // Punkt-Operatoren haben den hoechste verbindende Prioritaet
+    if ( isMultiplyOperator(operator) )
+      return 1000;
+    // Strich-Operatoren haben Vorrang vor Vergleichen oder booleschen Operatoren
+    if ( isAdditionOperator(operator) )
+      return 100;
+    // Vergleichs-Operatoren haben Vorrang vor booleschen Operatoren
+    if ( isCompareOperator(operator) )
+      return 10;
+    // boolesche Operatoren haben den geringesten Rang
+    if ( isBooleanOperator(operator) ) {
+      if ( operator.equals("!") )
+        return 3;
+      if ( operator.equals("&") )
+        return 2;
+      if ( operator.equals("|") )
+        return 1;
+    }
+
+    return 0;
+  }
+
+  /**
+   * Liefert den Konnektivitaetswert des am meisten bindenden Operators.
+   * Unterklasse muessen diese Methode u.U. ueberschreiben, wenn durch
+   * Ueberschreiben der Methode {@link #getOperatorConnectivity(String)}
+   * die Prioritaeten der Operatoren veraendert werden.
+   */
+  protected int getMaximumOperatorConnectivity() {
+    return 1000;
+  }
+
+  /**
+   * Liefert die 2-stellige Operatoren, die zwei Operanden aneinander
+   * binden (Punkt-Operatoren).
+   * Unterklassen koennen diese Methode ueberschreiben und Zeichen hinzufuegen.
+   * @return <code>"/*^"</code>
+   * @deprecated wegen booleschen Operatoren muss eine Verbindungs-Prioritaet
+                 verwendet werden; ersetzt durch {@link #getOperatorConnectivity(String)}
+   */
+  public String getConnectingOperatorChars() {
+    return "/*^";
+  }
+
+  /**
+   * Prueft, ob es sich bei einem 2-stelligen Operator um einen verbindenen
+   * Operator handelt (Punkt-Operator).
+   * @param operator 2-stelliger Operator
+   * @see #getConnectingOperatorChars()
+   * @deprecated wegen booleschen Operatoren muss eine Verbindungs-Prioritaet
+                 verwendet werden; ersetzt durch {@link #getOperatorConnectivity(String)}
+   */
+  public boolean isConnectingOperator(String operator) {
+    return getConnectingOperatorChars().contains(operator);
+  }
+
+  ///////////////////////////////////////////////////////////////////
+  ///////////////////   Methoden fuer Parsen  ///////////////////////
+  ///////////////////////////////////////////////////////////////////
+  /**
+   * Erstellt einen Operator-Baum aus einem Formel-String.
+   * @param rule Formel
+   */
+  public OperationTree parse(String rule) {
+    openBrackets = new StringBuffer();
+//    // Probleme, wenn Formel mit einem geklammerten Ausdruck beginnt
+//    // z.B. "(17+7)*2+1" -> *2+1 wird nicht ausgewertet
+//    // Loesung: Gesamten Ausdruck nochmal klammern
+//    rule = "("+rule.trim()+")";
+//    tok  = new PushbackStringTokenizer(rule,delimiter,true);
+//    return new OperationTree( parseRulePart() );
+    tok  = new PushbackStringTokenizer(rule,delimiter,true);
+    try {
+      return new OperationTree( parseRule() );
+    } catch (NoSuchElementException err) {
+      throwParseError( LangUtil.RESOURCE.getString("OperationTree.err.UnexpectedEOR") );
+    } catch (Exception err) {
+      throwParseError( LangUtil.RESOURCE.getString("OperationTree.err.UnexpectedError"), err );
+    }
+    // kann nicht vorkommen!!
+    return null;
+  }
+
+//  /**
+//   * Parst die naechste Teil-Formel aus dem Tokenizer {@link #tok}. Eine (geklammerter)
+//   * Teilformel ist eine durch Strich-Operatoren verbundene Kette von
+//   * {@linkplain #parseOperand() Operanden}.
+//   */
+//  protected final BinaryTreeNode parseRulePart() {
+//    BinaryTreeNode rulePart    = null;
+//    BinaryTreeNode nextOperand = null;
+//    String         operator    = null;
+//
+//    // Ersten (linken) Operand parsen
+//    String token = nextNonWSToken();
+//    // oeffnende Klammer
+//    if ( isOpeningBracket(token) )
+//      openBrackets.insert(0,token);
+//    else
+//      tok.pushback();
+//
+//    rulePart = parseOperand();
+//    while ( tok.hasMoreTokens() ) {
+//      // Operator parsen (kann nur ein Strich- oder Bool-Operator sein!)
+//      operator = nextNonWSToken();
+//
+//      // Sonderfall: schliessende Klammer
+//      // -> Klammerung ueberpruefen und Teil-Formel beenden
+//      if ( isClosingBracket(operator) ) {
+//        if ( !checkCorrespondingBrackets(openBrackets.charAt(0),operator.charAt(0)) )
+//          throwParseError("Bracket '" + operator + "' can not close '" + openBrackets.charAt(0) + "'");
+//        openBrackets.deleteCharAt(0);
+//        return rulePart;
+//      }
+//
+//      // Pruefen, ob es wirklich ein Operator ist
+//      if ( !isOperatorChar(operator) )
+//        throwParseError("Illegal operator '" + operator + "'");
+//
+//      // Sonderfall: boolesche Operatoren u.U. 2-stellig (<=, >=, !=, <>, ==)
+//      String nToken = nextNonWSToken();
+//      if ( operator.equals("<") && nToken.equals("=") ||
+//           operator.equals(">") && nToken.equals("=") ||
+//           operator.equals("=") && nToken.equals("=") ||
+//           operator.equals("!") && nToken.equals("=") ||
+//           operator.equals("<") && nToken.equals(">") )
+//        operator += nToken;
+//      else
+//        tok.pushback();
+//
+//      // Naechsten Operand parsen
+//      nextOperand = parseOperand();
+//
+//      // Teil zusammensetzen
+//      rulePart = new OperationTree.OperatorNode(operator,rulePart,nextOperand);
+//    }
+//    // keine Token mehr, aber noch offene Klammern
+//    if ( openBrackets.length() > 0 )
+//      throwParseError("Bracket"+(openBrackets.length() > 1 ? "s" : "")+" '"+openBrackets.toString()+"' not closed!");
+//    return rulePart;
+//  }
+//
+//  /**
+//   * Parst den naechsten Operand aus dem Tokenizer {@link #tok}. Ein Operand ist eine
+//   * durch Punkt-Operatoren verbundene Kette von {@linkplain #parseLiteral() Literalen}
+//   * und geklammerten {@linkplain #parseRulePart() Teil-Formeln}.<br>
+//   */
+//  protected final BinaryTreeNode parseOperand() {
+//    BinaryTreeNode operand = null;
+//    BinaryTreeNode nextLiteral = null;
+//    String operator = null;
+//
+//    // Erstes (linkes) Literal parsen
+//    String token = nextNonWSToken();
+//    // oeffnende Klammer direkt am Anfang
+//    // -> Literal besteht aus kompletter Teilformel
+//    if (isOpeningBracket(token)) {
+//      tok.pushback();
+//      operand = parseRulePart();
+//    } else {
+//      // Sonderfall: Operand startet mit Minus-Zeichen (z.B. '-(1+2)' oder '-abs(-4)')
+//      //             -> folgende
+//      if ( token.equals("-") )
+//        operand = new OperationTree.OperatorNode("*", new OperationTree.ConstantNode(-1.0),  parseOperand());
+//      else {
+//        tok.pushback();
+//        operand = parseLiteral();
+//      }
+//    }
+//    while (tok.hasMoreTokens()) {
+//      // Operator parsen
+//      operator = nextNonWSToken();
+//      // wenn schliessende Klammer oder Strich-/Bool-Operator
+//      // -> Operand beenden
+//      if (isClosingBracket(operator) || !isMultiplyOperator(operator)) {
+//        tok.pushback();
+//        return operand;
+//      }
+//      // Pruefen, ob es wirklich ein Operator ist
+//      if ( !isOperatorChar(operator) )
+//        throwParseError("Illegal operator '" + operator + "'");
+//
+//      // Naechstes Literal
+//      token = nextNonWSToken();
+//      tok.pushback();
+//      // oeffnende Klammer
+//      // -> naechstes Literal ist eine komplette Teilformel
+//      if (isOpeningBracket(token))
+//        nextLiteral = parseRulePart();
+//      else
+//        nextLiteral = parseLiteral();
+//
+//      // Operand zusammensetzen
+//      operand = new OperationTree.OperatorNode(operator, operand, nextLiteral);
+//    }
+//
+//    return operand;
+//  }
+
+  /**
+   * Liesst ein weiteres Zeichen aus dem Tokenizer und fuegt dies gegebenfalls
+   * dem Operator hinzu. Dies ist z.B. bei den Vergleichsoperatoren
+   * <=, >=, ==, != und == notwendig.
+   * @param operator Operator
+   */
+  private String expandOperator(String operator) {
+      // Sonderfall: boolesche Operatoren u.U. 2-stellig (<=, >=, !=, <>, ==)
+      String nToken = nextNonWSToken();
+      if ( operator.equals("<") && nToken.equals("=") ||
+           operator.equals(">") && nToken.equals("=") ||
+           operator.equals("=") && nToken.equals("=") ||
+           operator.equals("!") && nToken.equals("=") ||
+           operator.equals("<") && nToken.equals(">") )
+        operator += nToken;
+      else
+        pushbackWithWSToken();
+      return operator;
+  }
+
+  /**
+   * Prueft, ob der aktuelle Operand oder die Teil-Formel aufrund einer
+   * schliessende Klammer oder einem Parameter-Trennzeichen abgeschlossen
+   * werden muss.
+   * @param token aktuelles Zeichen
+   */
+  private RuleClosingType checkRuleClosing(String token) {
+    // Operand/Teil-Formel wird nur bei schliessender Klammer oder
+    // Parameter-Trennzeichen beendet
+    if ( !isClosingBracket(token) &&
+         !isParameterSeperator(token) )
+      return RuleClosingType.none;
+
+    // aktuelle Klammerung ermitteln
+    if ( openBrackets.length() == 0 )
+        throwParseError( LangUtil.RESOURCE.getString("OperationTree.err.TokenNotExpected",token) );
+    char openBracket = openBrackets.charAt(0);
+
+    // Schliessende Klammer
+    if ( isClosingBracket(token) ) {
+        // Flag, ob Klammer eine Funktion mit Parametern f(.,.,...) beendet.
+        // In diesem Fall liegt die verbleibende Anzahl (0) an Parametern
+        // auf dem Stack
+        boolean funcEnding = (openBracket == '0');
+        if ( funcEnding )
+          // korrespondierende oeffnende Klammer liegt vor Parameter-Wert
+          // auf Stack
+          openBracket = openBrackets.charAt(1);
+
+      // Wenn keine oeffnende Klammer auf Stack liegt (sondern ein Parameter-Zaehler)
+      // kann Klammer nicht schliessen, da noch ein Parameter erwartet wird
+      if ( !isOpeningBracket(String.valueOf(openBracket)) )
+        throwParseError( LangUtil.RESOURCE.getString("OperationTree.err.MoreParamsExpected",openBracket) );
+      if ( !checkCorrespondingBrackets(openBracket,token.charAt(0)) )
+        throwParseError( LangUtil.RESOURCE.getString("OperationTree.err.UnexpectedBracket",token,openBracket) );
+
+      return funcEnding ? RuleClosingType.func_pram : RuleClosingType.rule_part;
+    }
+
+    // Trenner zwischen Funktions-Parametern
+    if ( isParameterSeperator(token) ) {
+      if ( isOpeningBracket(String.valueOf(openBracket)) )
+        throwParseError( LangUtil.RESOURCE.getString("OperationTree.err.TokenNotExpected",token) );
+      return RuleClosingType.func_pram;
+    }
+
+    return RuleClosingType.none;
+  }
+
+  /**
+   * Prueft, ob noch offene Klammern auf dem Stack liegen, obwohl keine
+   * Token mehr zu parsen sind. Ist dies der Fall wird eine Exception
+   * geworfen.
+   */
+  private void checkRemainingBrackets() {
+    // keine Token mehr, aber noch offene Klammern
+    if ( !tok.hasMoreTokens() && openBrackets.length() > 0 )
+      throwParseError( LangUtil.RESOURCE.getString("OperationTree.err.BracketsNotClosed",openBrackets.toString()) );
+  }
+
+  /**
+   * Parst eine komplette Formel, bis zum Ende der Eingabe-Formel oder
+   * einem Parameter-Trenner.
+   */
+  protected final BinaryTreeNode parseRule() {
+    String         operator     = null;
+    BinaryTreeNode rulePart     = null;
+    BinaryTreeNode nextOperand  = null;
+
+    // Ersten Formel-Teil parsen
+    rulePart = parseRulePart();
+
+    while ( tok.hasMoreTokens() ) {
+      // Operator parsen
+      operator = nextNonWSToken();
+
+      // Ende der Formel pruefen, kann eigentlich nur das Ende eines
+      // Funktions-Parameters sein, da schliessende Klammern sonst bereits
+      // entfernt wurden...
+      if ( checkRuleClosing(operator) != RuleClosingType.none ) {
+        pushbackWithWSToken();
+        return rulePart;
+      }
+
+      // Pruefen, ob es wirklich ein Operator ist
+      if ( !isOperatorChar(operator) )
+        throwParseError( LangUtil.RESOURCE.getString("OperationTree.err.IllegalOperator", operator) );
+      // Sonderfall: boolesche Operatoren u.U. 2-stellig (<=, >=, !=, <>, ==)
+      operator = expandOperator(operator);
+
+      // Naechsten Operand parsen
+      nextOperand = parseOperand( getOperatorConnectivity(operator) );
+
+      // Teil zusammensetzen
+      rulePart = new OperationTree.OperatorNode(operator,rulePart,nextOperand);
+    }
+
+    checkRemainingBrackets();
+
+    return rulePart;
+  }
+
+  /**
+   * Parst die naechste Teil-Formel aus dem Tokenizer {@link #tok}. Eine (geklammerter)
+   * Teilformel ist eine durch Strich-Operatoren verbundene Kette von
+   * {@linkplain #parseOperand(int) Operanden}.
+   */
+  protected final BinaryTreeNode parseRulePart() {
+    BinaryTreeNode rulePart    = null;
+    BinaryTreeNode nextOperand = null;
+    String         operator    = null;
+
+    // Ersten (linken) Operand parsen
+    String token = nextNonWSToken();
+    // oeffnende Klammer
+    if ( isOpeningBracket(token) )
+      openBrackets.insert(0,token);
+    else
+      pushbackWithWSToken();
+
+    rulePart = parseOperand( getMaximumOperatorConnectivity() );
+    while ( tok.hasMoreTokens() ) {
+      // Operator parsen
+      operator = nextNonWSToken();
+
+      // schliessende Klammer oder Parameter-Trenner beendet die Teil-Formel
+      RuleClosingType closingType = checkRuleClosing(operator);
+      if ( closingType != RuleClosingType.none ) {
+        // Wenn Teil-Formel beendet wird, dann schliessende Klammer
+        // vom Stack entfernen
+        if ( closingType == RuleClosingType.rule_part )
+          openBrackets.deleteCharAt(0);
+        // Wenn Functions-Parameter beendet wird, dann Token zuruecklegen,
+        // damit Beendigung der Formel (in uebergeordneter Methode)
+        // erkannt wird
+        if ( closingType == RuleClosingType.func_pram )
+          pushbackWithWSToken();
+        // (Teil-)Formel beenden
+        return rulePart;
+      }
+
+      // Pruefen, ob es wirklich ein Operator ist
+      if ( !isOperatorChar(operator) )
+        throwParseError( LangUtil.RESOURCE.getString("OperationTree.err.IllegalOperator", operator) );
+      // Sonderfall: boolesche Operatoren u.U. 2-stellig (<=, >=, !=, <>, ==)
+      operator = expandOperator(operator);
+
+      // Naechsten Operand parsen
+      nextOperand = parseOperand( getOperatorConnectivity(operator) );
+
+      // Teil zusammensetzen
+      rulePart = new OperationTree.OperatorNode(operator,rulePart,nextOperand);
+    }
+
+    checkRemainingBrackets();
+
+    return rulePart;
+  }
+
+  /**
+   * Parst den naechsten Operand aus dem Tokenizer {@link #tok}. Ein Operand ist eine
+   * durch Operatoren gleicher Konnektivitaet verbundene Kette von
+   * {@linkplain #parseLiteral() Literalen} und geklammerten
+   * {@linkplain #parseRulePart() Teil-Formeln}.<br>
+   * @param minOperandConn minimale Konnektivitaet fuer den Operanden (bei einem
+   *                       Operator mit kleinerer Konnektivitaet wird der
+   *                       Operand beendet)
+   */
+  protected final BinaryTreeNode parseOperand(int minOperatorConn) {
+    BinaryTreeNode operand = null;
+    BinaryTreeNode nextLiteral = null;
+    String operator = null;
+    int lastOperatorConn = this.getMaximumOperatorConnectivity();
+
+    // Erstes (linkes) Literal parsen
+    String token = nextNonWSToken();
+    // oeffnende Klammer direkt am Anfang
+    // -> Literal besteht aus kompletter Teilformel
+    if (isOpeningBracket(token)) {
+      pushbackWithWSToken();
+      operand = parseRulePart();
+    } else {
+      // Sonderfall: Operand startet mit Minus-Zeichen (z.B. '-(1+2)' oder '-abs(-4)')
+      //             -> folgende
+      if ( token.equals("-") )
+        operand = new OperationTree.OperatorNode("*", new OperationTree.ConstantNode(-1.0),  parseOperand(getOperatorConnectivity("*")));
+      else {
+        pushbackWithWSToken();
+        operand = parseLiteral();
+      }
+    }
+    while (tok.hasMoreTokens()) {
+      // Operator parsen
+      operator = nextNonWSToken();
+      // schliessende Klammer oder Parameter-Trenner beendet den Operand
+      if ( checkRuleClosing(operator) != RuleClosingType.none) {
+        pushbackWithWSToken();
+        return operand;
+      }
+
+      // Pruefen, ob es wirklich ein Operator ist
+      if ( !isOperatorChar(operator) )
+        throwParseError( LangUtil.RESOURCE.getString("OperationTree.err.IllegalOperator", operator) );
+      // Sonderfall: boolesche Operatoren u.U. 2-stellig (<=, >=, !=, <>, ==)
+      operator = expandOperator(operator);
+
+      int operatorConn = getOperatorConnectivity(operator);
+      // Operator mit geringerer Konnektivitaet beendet den Operand
+      if ( operatorConn < minOperatorConn ) {
+        for (int i=0; i<operator.length(); i++)
+        pushbackWithWSToken();
+        return operand;
+      }
+
+//      // Operator mit hoeherer Konnektivitaet erzeugt einen neuen Operand
+//      // Ausnahme: erste Operation im Operand ('operand' hat noch keine Kinder)!
+//      if ( operatorConn > minOperandConn && !operand.isLeaf() ) {
+
+      // Operator mit hoeherer Konnektivitaet, als der letzte Operator, erzeugt
+      // einen neuen Operand
+      if ( operatorConn > lastOperatorConn ) {
+        BinaryTreeNode operandHigher = parseOperand(operatorConn);
+        // Das letzte Literal ist der erste Operand von 'operandHigher'
+        operand.setRightChild(
+          new OperationTree.OperatorNode(
+                  operator,
+                  operand.getRightChild(),
+                  operandHigher
+          )
+        );
+        // mit naechstem Operator fortfahren
+        lastOperatorConn = operatorConn;
+        continue;
+      }
+
+      // Naechstes Literal
+      token = nextNonWSToken();
+      pushbackWithWSToken();
+      // oeffnende Klammer
+      // -> naechstes Literal ist eine komplette Teilformel
+      if (isOpeningBracket(token))
+        nextLiteral = parseRulePart();
+      else
+        nextLiteral = parseLiteral();
+
+      // Operand zusammensetzen
+      operand = new OperationTree.OperatorNode(operator, operand, nextLiteral);
+
+      lastOperatorConn = operatorConn;
+    }
+
+    return operand;
+  }
+
+
+
+  /**
+   * Parst das naechste Literal aus dem Tokenizer {@link #tok}. Ein Literal ist eine numerische
+   * Konstante, ein Alias oder ein 1-stelliger Operator auf einer geklammerten
+   * {@linkplain #parseRulePart() Teil-Formel}. Diese Methode unterstuetzt
+   * <ul>
+   *   <li>als 1-stellige Operatoren
+   *      <ul>
+   *         <li>Betrag: {@code "abs(.)"}</li>
+   *         <li>Wurzel: {@code "sqr(.)"} oder {@code "sqrt(.)"}</li>
+   *         <li>Runden: {@code "rnd(.)"} oder {@code "round(.)"}</li>
+   *         <li>Abschneiden: {@code "int(.)"} oder {@code "trunc(.)"}</li>
+   *         <li>boolesches NICHT: {@code "!(.)"} oder {@code "not(.)"}</li>
+   *         <li>Test auf "Not a Number" (NaN): {@code "isNaN(.)"}</li>
+   *         <li>Sinus: {@code "sin(.)"}</li>
+   *         <li>Cosinus: {@code "cos(.)"}</li>
+   *         <li>Tangens: {@code "tan(.)"}</li>
+   *         <li>Arcus-Sinus: {@code "arcsin(.)"} oder {@code "asin(.)"}</li>
+   *         <li>Arcus-Cosinus: {@code "arccos(.)"} oder {@code "acos(.)"}</li>
+   *         <li>Arcus-Tangens: {@code "arctan(.)"} oder {@code "atan(.)"}</li>
+   *         <li>Exponentialfunktion: {@code "exp(.)"}</li>
+   *         <li>Logarithmus zur Basis e: {@code "ln(.)"}</li>
+   *         <li>Logarithmus zur Basis 10: {@code "log(.)"}</li>
+   *         <li>Umwandlung Zahl-zu-String: {@code "str(.)"}</li>
+   *         <li>Umwandlung String-zu-Zahl: {@code "val(.)"}</li>
+   *         <li>Laenge eines Strings: {@code "len(.)"}</li>
+   *         <li>Umwandlung in Gross-Buchstaben: {@code "toupper(.)"}</li>
+   *         <li>Umwandlung in Klein-Buchstaben: {@code "tolower(.)"}</li>
+   *       </ul></li>
+   *   <li>als Alias (0-stellige Operatoren)
+   *       <ul>
+   *         <li>Zufallszahl zwischen 0 und 1: {@code "rand"} oder {@code "random"}</li>
+   *         <li>"Not a number" (NaN): {@code "NaN"}</li>
+   *       </ul></li>
+   *   <li>als Sonderfaelle
+   *       <ul>
+   *         <li>IF .. THEN .. ELSE ..: {@code "ITE(.,.,.)"}</li>
+   *       </ul></li>
+   * </ul>
+   * <b>Sub-Klassen muessen diese Methode erweitern, wenn z.B. (alphanumerische)
+   * Variablen oder zusaetzliche 1-stellige Operatoren beruecksichtigt werden
+   * sollen!!</b>
+   */
+  protected BinaryTreeNode parseLiteral() {
+    String token = nextNonWSToken().toLowerCase();
+
+    // Sonderfall: in Anfuehrungsstriche gekapselte String-Konstante
+    if ( isStringEncapsulationChar(token) ) {
+      // Token (Anfuehrungsstrichen) erweitern um alles, bis zum naechsten
+      // Anfuehrungsstrich gleicher Art
+      String encChar = token;
+      // Bemerkung: tok.nextToken(encChar) funktioniert nicht so richtig,
+      //            wohl wegen PushBack-Funktionalitaet. Zudem aendert
+      //            dieser Aufruf die Delimiter dauerhaft!
+      do {
+        token += tok.nextToken();
+      } while (!token.endsWith(encChar));
+    }
+
+
+    // Betrag, Wurzel, Runden
+    if ( token.equals("abs") ||
+         token.equals("sqr") || token.equals("sqrt") ||
+         token.equals("rnd") || token.equals("round") ||
+         token.equals("int") || token.equals("trunc") ||
+         token.equals("!")   || token.equals("not") ||
+         token.equals("isnan") ||
+         token.equals("sin") ||
+         token.equals("cos") ||
+         token.equals("tan") ||
+         token.equals("arcsin") || token.equals("asin") ||
+         token.equals("arccos") || token.equals("acos") ||
+         token.equals("arctan") || token.equals("atan") ||
+         token.equals("exp") ||
+         token.equals("log") ||
+         token.equals("ln") ||
+         token.equals("str")     || token.equals("val") ||
+         token.equals("len") ||
+         token.equals("toupper") || token.equals("tolower") ) {
+      return new OperationTree.UnaryOperatorNode(token, parseRulePart());
+    }
+    // Zufallszahl oder NaN-Konstante
+    if ( token.equals("rand") || token.equals("random") ||
+         token.equals("nan")  || token.equals("curr_millis")) {
+      return new OperationTree.ConstantAliasNode(token);
+    }
+    // ITE(a,b,c) = IF a THEN b ELSE c
+    if ( token.equals("ite") ) {
+        // Parameter fuer ITE parsen
+        BinaryTreeNode[] iteParam = parseFunctionParameters("ITE",3);
+        // Baum fuer ITE
+        return new OperationTree.ITENode(token,iteParam[0],iteParam[1],iteParam[2]);
+    }
+
+    // REGEX(string,regexpr) = Regular Expression
+    if ( token.equals("regex") ) {
+      // Parameter fuer REGEX parsen
+      BinaryTreeNode[] regexParam = parseFunctionParameters("REGEX",2);
+      // Baum fuer REGEX
+      return new OperationTree.OperatorNode(token,regexParam[0],regexParam[1]);
+    }
+
+    // SPLIT(string,regexpr) = String-Split
+    if ( token.equals("split") ) {
+      // Parameter fuer SPLIT parsen
+      BinaryTreeNode[] splitParam = parseFunctionParameters("SPLIT",3);
+      // Baum fuer SPLIT
+      return new OperationTree.MultiParamOperatorNode(token,null,splitParam);
+    }
+
+    // SUBSTR(string,startPos_inkl,endPos_exkl) = Teil-String
+    if ( token.equals("substr") ) {
+      // Parameter fuer SUBSTR parsen
+      BinaryTreeNode[] substrParam = parseFunctionParameters("SUBSTR",3);
+      // Baum fuer SPLIT
+      return new OperationTree.MultiParamOperatorNode(token,null,substrParam);
+    }
+
+    // REPLALL(string,pattern,replacement) = String-Ersetzung
+    if ( token.equals("replall") ) {
+      // Parameter fuer REPLALL parsen
+      BinaryTreeNode[] substrParam = parseFunctionParameters("REPLALL",3);
+      // Baum fuer REPLALL
+      return new OperationTree.MultiParamOperatorNode(token,null,substrParam);
+    }
+
+    // sonst: Konstante
+    return new OperationTree.ConstantNode(getConstantFromString(token));
+  }
+
+  /**
+   * Parst die Funktions-Parameter fuer eine Funktion F(.,.,.,.).
+   * @param operator Name des Operators (nur fuer Exception-Beschreibung)
+   * @param paramCount Anzahl der erwarteten Parameter
+   */
+  private BinaryTreeNode[] parseFunctionParameters(String operator, int paramCount) {
+    BinaryTreeNode[] paramNode = new BinaryTreeNode[paramCount];
+
+    // naechstes Token muss eine oeffnende Klammer sein!
+    String token = nextNonWSToken();
+    if ( !token.equals("(") )
+    throwParseError( LangUtil.RESOURCE.getString("OperationTree.err.IllegalOperatorSyntax", operator, token) );
+    openBrackets.insert(0,"(");
+
+    openBrackets.insert(0, String.valueOf(paramCount-1)); // noch X weitere Parameter (Trenner) erwartet
+    // parCount-1 Parameter parsen
+    for (int i=0; i<paramCount-1; i++) {
+      // Parameter fuer ITE lesen
+      paramNode[i] = parseRule();
+      if ( !isParameterSeperator( tok.nextToken() ) ) // Seperator entfernen
+        throwParseError( LangUtil.RESOURCE.getString("OperationTree.err.ParamSepExpected") );
+      openBrackets.replace(0, 1, String.valueOf(paramCount-(i+2))); // noch X-1 weiterer Parameter (Trenner) erwartet
+    }
+    // den letzten Parameter parsen
+    paramNode[paramNode.length-1] = parseRule();
+    // Funktion-schliessende Klammer entfernen (Pruefung auf Konsistenz mit
+    // oeffnender Klammer erfolgte bereits in checkRuleClosing(.)
+    tok.nextToken();
+    // Parameter-Zaehler von Stack entfernen
+    openBrackets.deleteCharAt(0);
+    // Funktion-oeffnende Klammer von Stack entfernen
+    openBrackets.deleteCharAt(0);
+
+    return paramNode;
+  }
+
+  ///////////////////////////////////////////////////////////////////
+  //////////////////////   Hilfsmethoden   //////////////////////////
+  ///////////////////////////////////////////////////////////////////
+  /**
+   * Wirft eine {@link IllegalArgumentException} mit der angegebenen Fehlermeldung.
+   * Als zusaetzlicher Hinweis wird das Formel-Praefix ausgegeben nach dem
+   * der Fehler aufgetreten ist.
+   * @param mess Fehler-Meldung
+   */
+  protected void throwParseError(String mess) {
+    throwParseError(mess,null);
+  }
+
+  /**
+   * Wirft eine {@link IllegalArgumentException} mit der angegebenen Fehlermeldung.
+   * Als zusaetzlicher Hinweis wird das Formel-Praefix ausgegeben nach dem
+   * der Fehler aufgetreten ist.
+   * @param mess Fehler-Meldung
+   * @param err  verursachender Fehler
+   */
+  protected void throwParseError(String mess, Throwable err) {
+    String errorPos = tok.getReadTokens();
+//    // Die Klammer entfernen, die am Anfang kuenstlich eingefuegt wurde
+//    errorPos = errorPos.substring(1);
+    if ( err != null )
+      throw new IllegalArgumentException( LangUtil.RESOURCE.getString("OperationTree.err.ParseErrorMess", errorPos, mess), err );
+    else
+      throw new IllegalArgumentException( LangUtil.RESOURCE.getString("OperationTree.err.ParseErrorMess", errorPos, mess) );
+  }
+
+  /**
+   * Liefert einen Double- oder String-Wert aus einem String. String-Konstanten
+   * muessen in " oder ' gekapselt sein, um als solche interpretiert zu werden.
+   * Die Wildcards {@code TRUE} und {@code FALSE} werden in 1 bzw. 0 umgewandelt.
+   * @param token umzuwandelnde Zeichenkette
+   * @exception IllegalArgumentException falls die Umwandlung nicht vorgenommen
+   *            werden kann
+   */
+  protected Object getConstantFromString(String token) {
+    // Sonderfall: String-Konstante in Anfuehrungsstrichen
+    if ( token.length()>0 && isStringEncapsulationChar(token.substring(0,1)) )
+      return token.substring(1, token.length()-1);
+    // Sonderfall: TRUE/FALSE als Wildcards fuer 1/0
+    if ( token.equalsIgnoreCase("TRUE") )
+      return 1;
+    if ( token.equalsIgnoreCase("FALSE") )
+      return 0;
+    // Sonst eine numerische Konstante
+    return getDoubleFromString(token);
+  }
+
+  /**
+   * Liefert einen Integer-Wert aus einem String.
+   * @param token umzuwandelnde Zeichenkette
+   * @exception IllegalArgumentException falls die Umwandlung nicht vorgenommen
+   *            werden kann
+   */
+  protected int getIntFromString(String token) {
+    token = token.trim();
+    try {
+      return Integer.parseInt(token);
+    }
+    catch (Exception err) {
+      throwParseError( LangUtil.RESOURCE.getString(
+                                 "OperationTree.err.IllegalCharacter",
+                                 token,
+                                 LangUtil.RESOURCE.getString("OperationTree.Integer")
+      ));
+    }
+    return 0;
+  }
+
+  /**
+   * Liefert einen Double-Wert aus einem String.
+   * @param token umzuwandelnde Zeichenkette
+   * @exception IllegalArgumentException falls die Umwandlung nicht vorgenommen
+   *            werden kann
+   */
+  protected double getDoubleFromString(String token) {
+    token = token.trim();
+    // Sonderfall: Bei alleinstehender negativer Konstante ist im Token nur
+    //             das Minus-Zeichen enthalten! Zahl-Token muss angehaengt werden.
+    if ( token.equals("-") )
+      token += nextNonWSToken();
+
+    try {
+      return Double.parseDouble(token);
+    }
+    catch (Exception err) {
+      throwParseError( LangUtil.RESOURCE.getString(
+                               "OperationTree.err.IllegalCharacter",
+                               token,
+                               LangUtil.RESOURCE.getString("OperationTree.Number")
+      ));
+    }
+    return 0;
+  }
+
+  /**
+   * Liefert das naechste Token aus dem Tokenizer, das nicht ein White-Space
+   * ist.
+   */
+  protected String nextNonWSToken() {
+    String token = null;
+    while ( (token = tok.nextToken()).trim().equals("") );
+    return token.trim();
+  }
+
+  /**
+   * Legt solange Token zurueck auf den Tokenizer, bis das zurueckgelegte
+   * Token <b>kein</b> White-Space ist.
+   */
+  protected void pushbackWithWSToken() {
+    while ( tok.pushback().trim().equals("") );
+  }
+
+}

Modified: trunk/src/schmitzm/lang/tree/TreeNode.java
===================================================================
--- trunk/src/schmitzm/lang/tree/TreeNode.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/lang/tree/TreeNode.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,150 +1,168 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.lang.tree;
-
-/**
- * Diese Klasse stellt einen Knoten in einem Baum dar.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public abstract class TreeNode<E> {
-  /** Speichert den Vater-Knoten. */
-  protected TreeNode<E> parent = null;
-  /** Speichert das Objekt, das in dem Knoten gespeichert wird. */
-  protected E object = null;
-
-  /**
-   * Erzeugt einen Wurzel-Knoten ohne Nachfolger.
-   */
-  public TreeNode() {
-    this((E)null);
-  }
-
-  /**
-   * Erzeugt einen Wurzel-Knoten ohne Nachfolger.
-   * @param object Objekt, das in dem Knoten gespeichert wird
-   */
-  public TreeNode(E object) {
-    this(object, null);
-  }
-
-  /**
-   * Erzeugt einen Blatt-Knoten.
-   * @param parent direkter Vorgaenger-Knoten
-   */
-  public TreeNode(TreeNode<E> parent) {
-    this(null, parent);
-  }
-
-  /**
-   * Erzeugt einen Blatt-Knoten.
-   * @param object Objekt, das in dem Knoten gespeichert wird
-   * @param parent direkter Vorgaenger-Knoten
-   */
-  public TreeNode(E object, TreeNode<E> parent) {
-    setObject( object );
-    setParent( parent );
-  }
-
-  /**
-   * Liefert den Wurzel-Knoten.
-   */
-  public TreeNode<E> getRoot() {
-    if ( this.isRoot() )
-      return this;
-    return parent.getRoot();
-  }
-
-  /**
-   * Prueft, ob ein Knoten als Vater- oder Kind-Knoten fuer diesen Knoten
-   * verwendet werden kann
-   * @param node zu pruefende Knoten
-   * @exception RuntimeException falls der Knoten nicht geeignet ist
-   */
-  public abstract void checkNode(TreeNode<E> node);
-
-  /**
-   * Prueft, ob es sich um einen Wurzelknoten handelt.
-   * @return <code>true<code> gdw. der Knoten keinen Vater hat
-   * @see #getParent()
-   */
-  public boolean isRoot() {
-    return getParent() == null;
-  }
-
-  /**
-   * Prueft, ob es sich um einen Blattknoten handelt.
-   * @return <code>true<code> gdw. alle Kinder {@code null} sind
-   */
-  public boolean isLeaf() {
-    for (int i=0; i<getChildCount(); i++)
-      if ( getChild(i) != null )
-        return false;
-    return true;
-  }
-
-  /**
-   * Prueft, ob es sich um einen inneren Knoten handelt.
-   * @return <code>true<code> gdw. der Knoten keine Wurzel und kein Blatt ist
-   */
-  public boolean isInnerNode() {
-    return !isRoot() && !isLeaf();
-  }
-
-  /**
-   * Liefert den direkten Vaterknoten.
-   */
-  public TreeNode<E> getParent() {
-    return parent;
-  }
-
-  /**
-   * Setzt den direkten Vorgaenger-Knoten
-   * @param parent neuer direkter Vorgaenger
-   */
-  public void setParent(TreeNode<E> parent) {
-    checkNode(parent);
-    this.parent = parent;
-  }
-
-  /**
-   * Liefert die Anzahl der Kindknoten.
-   */
-  public abstract int getChildCount();
-
-  /**
-   * Liefert einen Kindknoten.
-   * @param i Index (beginnend bei 0)
-   */
-  public abstract TreeNode<E> getChild(int i);
-
-  /**
-   * Setzt einen Kindknoten.
-   * @param i Index (beginnend bei 0)
-   * @param child ein Kindknoten
-   */
-  public abstract void setChild(int i, TreeNode<E> child);
-
-  /**
-   * Liefert das Objekt, das in dem Knoten gespeichert ist.
-   */
-  public E getObject() {
-    return object;
-  }
-
-  /**
-   * Setzt das Objekt, das in dem Knoten gespeichert ist.
-   */
-  public void setObject(E object) {
-    this.object = object;
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.lang.tree;
+
+/**
+ * Diese Klasse stellt einen Knoten in einem Baum dar.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public abstract class TreeNode<E> {
+  /** Speichert den Vater-Knoten. */
+  protected TreeNode<E> parent = null;
+  /** Speichert das Objekt, das in dem Knoten gespeichert wird. */
+  protected E object = null;
+
+  /**
+   * Erzeugt einen Wurzel-Knoten ohne Nachfolger.
+   */
+  public TreeNode() {
+    this((E)null);
+  }
+
+  /**
+   * Erzeugt einen Wurzel-Knoten ohne Nachfolger.
+   * @param object Objekt, das in dem Knoten gespeichert wird
+   */
+  public TreeNode(E object) {
+    this(object, null);
+  }
+
+  /**
+   * Erzeugt einen Blatt-Knoten.
+   * @param parent direkter Vorgaenger-Knoten
+   */
+  public TreeNode(TreeNode<E> parent) {
+    this(null, parent);
+  }
+
+  /**
+   * Erzeugt einen Blatt-Knoten.
+   * @param object Objekt, das in dem Knoten gespeichert wird
+   * @param parent direkter Vorgaenger-Knoten
+   */
+  public TreeNode(E object, TreeNode<E> parent) {
+    setObject( object );
+    setParent( parent );
+  }
+
+  /**
+   * Liefert den Wurzel-Knoten.
+   */
+  public TreeNode<E> getRoot() {
+    if ( this.isRoot() )
+      return this;
+    return parent.getRoot();
+  }
+
+  /**
+   * Prueft, ob ein Knoten als Vater- oder Kind-Knoten fuer diesen Knoten
+   * verwendet werden kann
+   * @param node zu pruefende Knoten
+   * @exception RuntimeException falls der Knoten nicht geeignet ist
+   */
+  public abstract void checkNode(TreeNode<E> node);
+
+  /**
+   * Prueft, ob es sich um einen Wurzelknoten handelt.
+   * @return <code>true<code> gdw. der Knoten keinen Vater hat
+   * @see #getParent()
+   */
+  public boolean isRoot() {
+    return getParent() == null;
+  }
+
+  /**
+   * Prueft, ob es sich um einen Blattknoten handelt.
+   * @return <code>true<code> gdw. alle Kinder {@code null} sind
+   */
+  public boolean isLeaf() {
+    for (int i=0; i<getChildCount(); i++)
+      if ( getChild(i) != null )
+        return false;
+    return true;
+  }
+
+  /**
+   * Prueft, ob es sich um einen inneren Knoten handelt.
+   * @return <code>true<code> gdw. der Knoten keine Wurzel und kein Blatt ist
+   */
+  public boolean isInnerNode() {
+    return !isRoot() && !isLeaf();
+  }
+
+  /**
+   * Liefert den direkten Vaterknoten.
+   */
+  public TreeNode<E> getParent() {
+    return parent;
+  }
+
+  /**
+   * Setzt den direkten Vorgaenger-Knoten
+   * @param parent neuer direkter Vorgaenger
+   */
+  public void setParent(TreeNode<E> parent) {
+    checkNode(parent);
+    this.parent = parent;
+  }
+
+  /**
+   * Liefert die Anzahl der Kindknoten.
+   */
+  public abstract int getChildCount();
+
+  /**
+   * Liefert einen Kindknoten.
+   * @param i Index (beginnend bei 0)
+   */
+  public abstract TreeNode<E> getChild(int i);
+
+  /**
+   * Setzt einen Kindknoten.
+   * @param i Index (beginnend bei 0)
+   * @param child ein Kindknoten
+   */
+  public abstract void setChild(int i, TreeNode<E> child);
+
+  /**
+   * Liefert das Objekt, das in dem Knoten gespeichert ist.
+   */
+  public E getObject() {
+    return object;
+  }
+
+  /**
+   * Setzt das Objekt, das in dem Knoten gespeichert ist.
+   */
+  public void setObject(E object) {
+    this.object = object;
+  }
+}

Modified: trunk/src/schmitzm/swing/BooleanInputOption.java
===================================================================
--- trunk/src/schmitzm/swing/BooleanInputOption.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/BooleanInputOption.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,100 +1,118 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+import javax.swing.JCheckBox;
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+/**
+ * Diese Klasse stellt eine boolsche Eingabe-Option fuer das {@link MultipleOptionPane}
+ * dar. Diese wird durch eine {@link JCheckBox} dargestellt.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class BooleanInputOption extends InputOption {
+  /**
+   * Erzeugt eine neue Eingabe-Option.
+   * @param label    Beschreibung
+   * @param defValue gibt an, ob die Checkbox standardmaessig aktiviert ist
+   */
+  public BooleanInputOption(String label, boolean defValue) {
+    super(label,false);
+    // Bei einer Checkbox soll die Beschreibung nicht oberhalb
+    // des Eingabefeldes zu stehen, sondern mit der Checkbox in
+    // einer Zeile
+    // -> JLabel entfernen und statt dessen den Text der Checkbox setzen
+    this.remove( this.descLabel );
+    ((JCheckBox)inpComp).setText(label);
+    // Standardwert setzen
+    setValue( defValue );
+  }
 
-package schmitzm.swing;
-
-import javax.swing.JCheckBox;
-
-/**
- * Diese Klasse stellt eine boolsche Eingabe-Option fuer das {@link MultipleOptionPane}
- * dar. Diese wird durch eine {@link JCheckBox} dargestellt.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class BooleanInputOption extends InputOption {
-  /**
-   * Erzeugt eine neue Eingabe-Option.
-   * @param label    Beschreibung
-   * @param defValue gibt an, ob die Checkbox standardmaessig aktiviert ist
-   */
-  public BooleanInputOption(String label, boolean defValue) {
-    super(label,false);
-    // Bei einer Checkbox soll die Beschreibung nicht oberhalb
-    // des Eingabefeldes zu stehen, sondern mit der Checkbox in
-    // einer Zeile
-    // -> JLabel entfernen und statt dessen den Text der Checkbox setzen
-    this.remove( this.descLabel );
-    ((JCheckBox)inpComp).setText(label);
-    // Standardwert setzen
-    setValue( defValue );
-  }
-
-  /**
-   * Erzeugt eine neue Eingabe-Option. Diese ist standardmaessig deaktiviert.
-   * @param label Beschreibung
-   */
-  public BooleanInputOption(String label) {
-    this(label,false);
-  }
-
-  /**
-   * Erzeugt eine neue Instanz von {@link JCheckBox}.
-   */
-  protected JCheckBox createInputComponent() {
-    return new JCheckBox();
-  }
-
-  /**
-   * Liefert den Wert, der in der Option eingegeben wurde. Prueft zuerst
-   * auf Gueltigkeit und ruft dann {@link #performGetValue()} auf.
-   * @return <code>null</code> wenn die aktuelle Eingabe nicht zulaessig ist
-   *         (siehe {@link #isInputValid()})
-   */
-  public Boolean getValue() {
-    return (Boolean)super.getValue();
-  }
-
-  /**
-   * Liefert immer <code>true</code>, da keine speziellen Anforderungen
-   * an die Text-Eingabe gestellt werden.
-   */
-  protected boolean performIsInputValid() {
-    return true;
-  }
-
-  /**
-   * Liefert immer <code>false</code>, da es keine Leereingabe gibt. Eine nicht
-   * aktivierte Checkbox bedeutet den Wert FALSE.
-   */
-  protected boolean performIsInputEmpty() {
-    return false;
-  }
-
-  /**
-   * Liefert <code>true</code>, falls die Checkbox aktiviert ist.
-   * @return einen <code>boolean</code>-Wert (<b>kein</b> {@link Boolean}-Objekt!)
-   */
-  protected Boolean performGetValue() {
-    return ((JCheckBox)inpComp).isSelected();
-  }
-
-  /**
-   * (De)aktiviert die Checkbox.
-   * @param active definiert den neuen Status (muss vom Typ {@link Boolean} sein!)
-   * @return <code>false</code> falls kein {@link Boolean} uebergeben wird.
-   */
-  protected boolean performSetValue(Object active) {
-    if ( !(active instanceof Boolean) )
-      return false;
-    ((JCheckBox)inpComp).setSelected((Boolean)active);
-    return true;
-  }
-}
+  /**
+   * Erzeugt eine neue Eingabe-Option. Diese ist standardmaessig deaktiviert.
+   * @param label Beschreibung
+   */
+  public BooleanInputOption(String label) {
+    this(label,false);
+  }
+
+  /**
+   * Erzeugt eine neue Instanz von {@link JCheckBox}.
+   */
+  protected JCheckBox createInputComponent() {
+    return new JCheckBox();
+  }
+
+  /**
+   * Liefert den Wert, der in der Option eingegeben wurde. Prueft zuerst
+   * auf Gueltigkeit und ruft dann {@link #performGetValue()} auf.
+   * @return <code>null</code> wenn die aktuelle Eingabe nicht zulaessig ist
+   *         (siehe {@link #isInputValid()})
+   */
+  public Boolean getValue() {
+    return (Boolean)super.getValue();
+  }
+
+  /**
+   * Liefert immer <code>true</code>, da keine speziellen Anforderungen
+   * an die Text-Eingabe gestellt werden.
+   */
+  protected boolean performIsInputValid() {
+    return true;
+  }
+
+  /**
+   * Liefert immer <code>false</code>, da es keine Leereingabe gibt. Eine nicht
+   * aktivierte Checkbox bedeutet den Wert FALSE.
+   */
+  protected boolean performIsInputEmpty() {
+    return false;
+  }
+
+  /**
+   * Liefert <code>true</code>, falls die Checkbox aktiviert ist.
+   * @return einen <code>boolean</code>-Wert (<b>kein</b> {@link Boolean}-Objekt!)
+   */
+  protected Boolean performGetValue() {
+    return ((JCheckBox)inpComp).isSelected();
+  }
+
+  /**
+   * (De)aktiviert die Checkbox.
+   * @param active definiert den neuen Status (muss vom Typ {@link Boolean} sein!)
+   * @return <code>false</code> falls kein {@link Boolean} uebergeben wird.
+   */
+  protected boolean performSetValue(Object active) {
+    if ( !(active instanceof Boolean) )
+      return false;
+    ((JCheckBox)inpComp).setSelected((Boolean)active);
+    return true;
+  }
+}

Modified: trunk/src/schmitzm/swing/BrowseInputOption.java
===================================================================
--- trunk/src/schmitzm/swing/BrowseInputOption.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/BrowseInputOption.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,142 +1,160 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing;
-
-import java.awt.BorderLayout;
-import java.awt.Container;
-import java.awt.Dimension;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-
-import javax.swing.JButton;
-import javax.swing.JTextField;
-
-import schmitzm.swing.event.InputOptionAdapter;
-
-/**
- * Die <code>BrowseInputOption</code> erweitert die {@linkplain ManualInputOption manuelle Text-Eingabe}
- * um eine Browse-Aktion. Welche konkrete Aktion beim Klick auf den Browse-Button
- * ausgefuehrt wird, bestimmt die jeweinige Implementierung.<br>
- * Der Wert dieser Eingabe-Option stellt keinen Text dar, sondern ein
- * zugehoeriges Objekt. Um ein Objekt sowohl ueber eine manuelle Texteingabe,
- * als auch ueber die Browse-Aktion angeben zu koennen, spezifiziert
- * <code>BrowseInputOption</code> zwei Methoden ({@link #convertFromString(String)},
- * {@link #convertToString(Object)}), ueber die eine entsprechende Umwandung zu
- * implementieren ist.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public abstract class BrowseInputOption  extends ManualInputOption {
-  /** Speichert den aktuellen Wert der Eingabe-Option. */
-  protected Object object = null;
-  /** Container enthaelt das Text-Eingabefeld und den Browse-Button. */
-  protected Container inpCompCont = new Container();
-  /** Der Button fuer die Browse-Aktion. */
-  protected JButton browseButton = new JButton("...");
-
-  /**
-   * Erzeugt eine neue Eingabe-Option.
-   * @param label Beschreibung der Eingabe
-   * @param inputNeeded gibt an, ob eine Eingabe in der Option erforderlich ist
-   * @param defValue Standard-Belegung fuer die Eingabe-Option
-   */
-  public BrowseInputOption(String label, boolean inputNeeded, Object defValue) {
-    super(label, inputNeeded, null);
-    setValue(defValue);
-
-    // Browse-Button formatieren
-    browseButton.setPreferredSize( new Dimension(30,10) );
-    browseButton.addActionListener( new ActionListener() {
-      public void actionPerformed(ActionEvent e) {
-        browseAction();
-      }
-    });
-
-    // Eingabe-Feld formatieren
-    SwingUtil.setPreferredWidth(inpComp,200);
-    this.addInputOptionListener( new InputOptionAdapter() {
-      public void optionLostFocus(InputOption option) {
-        try {
-          setValue( convertFromString( ((JTextField)inpComp).getText() ) );
-        } catch (Exception err) {
-          ExceptionDialog.show(OPTION_COMPONENT,err,SwingUtil.RESOURCE.getString("Error"),SwingUtil.RESOURCE.getString("InvalidInputMess"));
-          setValue( getValue() );
-        }
-      }
-    });
-
-    // Neben dem Eingabefeld noch ein Browse-Button
-    inpCompCont.setLayout( new BorderLayout(10,0) );
-    inpCompCont.add(this.inpComp, BorderLayout.CENTER);
-    inpCompCont.add(this.browseButton, BorderLayout.EAST);
-    // normale Eingabe-Komponente durch Container ersetzen
-    remove(inpComp);
-    add(inpCompCont,BorderLayout.SOUTH);
-  }
-
-  /**
-   * Aktion des Browse-Button.
-   */
-  private void browseAction() {
-    Object newObj = performBrowse(this.getValue());
-    // Browse-Aktion abgebrochen
-    if ( newObj == null )
-      return;
-    this.setValue(newObj);
-  }
-
-  /**
-   * Liefert das zu der Text-Eingabe gehoerende Objekt.
-   */
-  protected Object performGetValue() {
-    return object;
-  }
-
-  /**
-   * Setzt den Wert der Eingabe-Option und befuellt entsprechend das
-   * Text-Feld der Eingabe-Option.
-   * @param newValue neuer Wert der Eingabe-Option (ein Objekt, <b>nicht</b> ein
-   *                 Wert fuer das Textfeld!)
-   * @return <code>false</code> falls das Objekt nicht in einen String umgewandelt
-   *         werden konnte
-   */
-  protected boolean performSetValue(Object newValue) {
-    try {
-      ((JTextField)inpComp).setText(convertToString(newValue));
-      this.object = newValue;
-      return true;
-    } catch (Exception err) {
-      return false;
-    }
-  }
-
-  /**
-   * Implementiert die Browse-Aktion die ausgefuehrt wird, wenn der Button
-   * der Eingabe-Option gedrueckt wird. Liefert ein neues Objekt fuer die
-   * Eingabe-Option.
-   * @param actValue aktueller Wert der Eingabe-Option
-   * @return <code>null</code> falls die Browse-Aktion abgebrochen wird
-   */
-  public abstract Object performBrowse(Object actValue);
-
-  /**
-   * Liefert das Objekt zu der Text-Eingabe der Option.
-   * @param objectStr Objekt-String
-   */
-  public abstract Object convertFromString(String objectStr);
-
-  /**
-   * Erzeugt einen (eindeutigen) String fuer ein Objekt.
-   * @param object Objekt
-   */
-  public abstract String convertToString(Object object);
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JButton;
+import javax.swing.JTextField;
+
+import schmitzm.swing.event.InputOptionAdapter;
+
+/**
+ * Die <code>BrowseInputOption</code> erweitert die {@linkplain ManualInputOption manuelle Text-Eingabe}
+ * um eine Browse-Aktion. Welche konkrete Aktion beim Klick auf den Browse-Button
+ * ausgefuehrt wird, bestimmt die jeweinige Implementierung.<br>
+ * Der Wert dieser Eingabe-Option stellt keinen Text dar, sondern ein
+ * zugehoeriges Objekt. Um ein Objekt sowohl ueber eine manuelle Texteingabe,
+ * als auch ueber die Browse-Aktion angeben zu koennen, spezifiziert
+ * <code>BrowseInputOption</code> zwei Methoden ({@link #convertFromString(String)},
+ * {@link #convertToString(Object)}), ueber die eine entsprechende Umwandung zu
+ * implementieren ist.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public abstract class BrowseInputOption  extends ManualInputOption {
+  /** Speichert den aktuellen Wert der Eingabe-Option. */
+  protected Object object = null;
+  /** Container enthaelt das Text-Eingabefeld und den Browse-Button. */
+  protected Container inpCompCont = new Container();
+  /** Der Button fuer die Browse-Aktion. */
+  protected JButton browseButton = new JButton("...");
+
+  /**
+   * Erzeugt eine neue Eingabe-Option.
+   * @param label Beschreibung der Eingabe
+   * @param inputNeeded gibt an, ob eine Eingabe in der Option erforderlich ist
+   * @param defValue Standard-Belegung fuer die Eingabe-Option
+   */
+  public BrowseInputOption(String label, boolean inputNeeded, Object defValue) {
+    super(label, inputNeeded, null);
+    setValue(defValue);
+
+    // Browse-Button formatieren
+    browseButton.setPreferredSize( new Dimension(30,10) );
+    browseButton.addActionListener( new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        browseAction();
+      }
+    });
+
+    // Eingabe-Feld formatieren
+    SwingUtil.setPreferredWidth(inpComp,200);
+    this.addInputOptionListener( new InputOptionAdapter() {
+      public void optionLostFocus(InputOption option) {
+        try {
+          setValue( convertFromString( ((JTextField)inpComp).getText() ) );
+        } catch (Exception err) {
+          ExceptionDialog.show(OPTION_COMPONENT,err,SwingUtil.RESOURCE.getString("Error"),SwingUtil.RESOURCE.getString("InvalidInputMess"));
+          setValue( getValue() );
+        }
+      }
+    });
+
+    // Neben dem Eingabefeld noch ein Browse-Button
+    inpCompCont.setLayout( new BorderLayout(10,0) );
+    inpCompCont.add(this.inpComp, BorderLayout.CENTER);
+    inpCompCont.add(this.browseButton, BorderLayout.EAST);
+    // normale Eingabe-Komponente durch Container ersetzen
+    remove(inpComp);
+    add(inpCompCont,BorderLayout.SOUTH);
+  }
+
+  /**
+   * Aktion des Browse-Button.
+   */
+  private void browseAction() {
+    Object newObj = performBrowse(this.getValue());
+    // Browse-Aktion abgebrochen
+    if ( newObj == null )
+      return;
+    this.setValue(newObj);
+  }
+
+  /**
+   * Liefert das zu der Text-Eingabe gehoerende Objekt.
+   */
+  protected Object performGetValue() {
+    return object;
+  }
+
+  /**
+   * Setzt den Wert der Eingabe-Option und befuellt entsprechend das
+   * Text-Feld der Eingabe-Option.
+   * @param newValue neuer Wert der Eingabe-Option (ein Objekt, <b>nicht</b> ein
+   *                 Wert fuer das Textfeld!)
+   * @return <code>false</code> falls das Objekt nicht in einen String umgewandelt
+   *         werden konnte
+   */
+  protected boolean performSetValue(Object newValue) {
+    try {
+      ((JTextField)inpComp).setText(convertToString(newValue));
+      this.object = newValue;
+      return true;
+    } catch (Exception err) {
+      return false;
+    }
+  }
+
+  /**
+   * Implementiert die Browse-Aktion die ausgefuehrt wird, wenn der Button
+   * der Eingabe-Option gedrueckt wird. Liefert ein neues Objekt fuer die
+   * Eingabe-Option.
+   * @param actValue aktueller Wert der Eingabe-Option
+   * @return <code>null</code> falls die Browse-Aktion abgebrochen wird
+   */
+  public abstract Object performBrowse(Object actValue);
+
+  /**
+   * Liefert das Objekt zu der Text-Eingabe der Option.
+   * @param objectStr Objekt-String
+   */
+  public abstract Object convertFromString(String objectStr);
+
+  /**
+   * Erzeugt einen (eindeutigen) String fuer ein Objekt.
+   * @param object Objekt
+   */
+  public abstract String convertToString(Object object);
+}

Modified: trunk/src/schmitzm/swing/ButtonGroup.java
===================================================================
--- trunk/src/schmitzm/swing/ButtonGroup.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/ButtonGroup.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,73 +1,91 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing;
-
 import javax.swing.AbstractButton;
 import javax.swing.ButtonModel;
 import javax.swing.JRadioButton;
-
-/**
- * Diese Klasse erweitert die {@link javax.swing.ButtonGroup javax.swing.ButtonGroup}
- * um die Option, alle Button der Gruppe wieder zu deaktivieren. Dies geschieht,
- * in dem immer ein "unsichtbarer" Dummy-Button Bestandteil der Gruppe ist,
- * der aktiviert wird, wenn alle anderen Butten deaktiviert sein sollen.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class ButtonGroup extends javax.swing.ButtonGroup {
-  private JRadioButton deactivationButton = new JRadioButton();
-
-  /**
-   * Erzeugt eine neue Button-Gruppe.
-   */
-  public ButtonGroup() {
-    super();
-    this.add(deactivationButton);
-  }
-
-  /**
-   * Deaktiviert alle Button der Gruppe.
-   */
-  public void setUnselected() {
-    deactivationButton.setSelected(true);
-  }
-
-//  /**
-//   * Liefert die Anzahl der Button innerhalb der Gruppe. Der Dummy-Button wird
-//   * dabei nicht mit gerechnet!
-//   */
-//  public int getButtonCount() {
-//    return super.getButtonCount()-1;
-//  }
-
-  /**
-   * Prueft, ob irgendein Button der Gruppe aktiviert ist. Der Dummy-Button wird
-   * dabei nicht beruecksichtigt!
-   */
-  public boolean isSelected(ButtonModel model) {
-    return super.isSelected(model) && !deactivationButton.isSelected();
-  }
-
-  /**
-   * Liefert den Button der Gruppe, der selektiert ist. Der Dummy-Button wird
-   * dabei nicht beruecksichtigt!
-   * @return <code>null</code> wenn kein Button selektiert ist
-   */
-  public AbstractButton getSelectedButton() {
-    for (int i=0; i<this.buttons.size(); i++) {
-      AbstractButton button = buttons.elementAt(i);
-      if ( button.isSelected() && button != deactivationButton )
-        return buttons.elementAt(i);
-    }
-    return null;
-  }
-}
+
+/**
+ * Diese Klasse erweitert die {@link javax.swing.ButtonGroup javax.swing.ButtonGroup}
+ * um die Option, alle Button der Gruppe wieder zu deaktivieren. Dies geschieht,
+ * in dem immer ein "unsichtbarer" Dummy-Button Bestandteil der Gruppe ist,
+ * der aktiviert wird, wenn alle anderen Butten deaktiviert sein sollen.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class ButtonGroup extends javax.swing.ButtonGroup {
+  private JRadioButton deactivationButton = new JRadioButton();
+
+  /**
+   * Erzeugt eine neue Button-Gruppe.
+   */
+  public ButtonGroup() {
+    super();
+    this.add(deactivationButton);
+  }
+
+  /**
+   * Deaktiviert alle Button der Gruppe.
+   */
+  public void setUnselected() {
+    deactivationButton.setSelected(true);
+  }
+
+//  /**
+//   * Liefert die Anzahl der Button innerhalb der Gruppe. Der Dummy-Button wird
+//   * dabei nicht mit gerechnet!
+//   */
+//  public int getButtonCount() {
+//    return super.getButtonCount()-1;
+//  }
+
+  /**
+   * Prueft, ob irgendein Button der Gruppe aktiviert ist. Der Dummy-Button wird
+   * dabei nicht beruecksichtigt!
+   */
+  public boolean isSelected(ButtonModel model) {
+    return super.isSelected(model) && !deactivationButton.isSelected();
+  }
+
+  /**
+   * Liefert den Button der Gruppe, der selektiert ist. Der Dummy-Button wird
+   * dabei nicht beruecksichtigt!
+   * @return <code>null</code> wenn kein Button selektiert ist
+   */
+  public AbstractButton getSelectedButton() {
+    for (int i=0; i<this.buttons.size(); i++) {
+      AbstractButton button = buttons.elementAt(i);
+      if ( button.isSelected() && button != deactivationButton )
+        return buttons.elementAt(i);
+    }
+    return null;
+  }
+}

Modified: trunk/src/schmitzm/swing/CaptionsChangeable.java
===================================================================
--- trunk/src/schmitzm/swing/CaptionsChangeable.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/CaptionsChangeable.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,43 +1,61 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing;
-
 import java.util.Map;
 
 import javax.swing.JPanel;
-
-/**
- * Dieses Interface ermoeglicht es die Beschriftungen in einer Swing-Komponente
- * (Labels und Buttons) nachtraeglich zu aendern. Zum Beispiel, wenn in einer
- * uebergeordneten Anwendung die Sprache gewechselt wird.<br>
- * Beim Aufruf von {@link #resetCaptions(Map)} muss die Komponente, welche
- * {@code CaptionsChangeable} implmentiert, gewaehrleisten, dass alle Beschriftungen
- * entsprechend der uebergebenen {@link Map} geaendert werden. Hierfuer sollte die
- * {@code CaptionsChangeable}-Komponente eindeutige Key-Konstanten implementieren,
- * ueber die die uebergeordnete Anwendung die neuen Beschriftungen in der Map
- * hinterlegen kann.<br>
- * Zudem sollte eine {@code CaptionsChangeable}-Komponente den {@link #resetCaptions(Map)}-Aufruf
- * an alle in ihr enthaltenen {@code CaptionsChangeable}-Komponenten weiterleiten.
- * {@link CaptionsChangeablePanel} stellt ein ansonsten normales {@link JPanel}
- * dar, welches diese Funktionalitaet bereits implementiert.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of
- *   Bonn/Germany)
- * @version 1.0
- */
-public interface CaptionsChangeable {
-  /**
-   * Aktualisiert alle Beschriftungen der Komponente entsprechend der uebergebenen
-   * Map.
-   * @param captionMap enthaelt die neuen Beschriftungen
-   */
-  public void resetCaptions(Map<String, Object> captionMap);
-}
+
+/**
+ * Dieses Interface ermoeglicht es die Beschriftungen in einer Swing-Komponente
+ * (Labels und Buttons) nachtraeglich zu aendern. Zum Beispiel, wenn in einer
+ * uebergeordneten Anwendung die Sprache gewechselt wird.<br>
+ * Beim Aufruf von {@link #resetCaptions(Map)} muss die Komponente, welche
+ * {@code CaptionsChangeable} implmentiert, gewaehrleisten, dass alle Beschriftungen
+ * entsprechend der uebergebenen {@link Map} geaendert werden. Hierfuer sollte die
+ * {@code CaptionsChangeable}-Komponente eindeutige Key-Konstanten implementieren,
+ * ueber die die uebergeordnete Anwendung die neuen Beschriftungen in der Map
+ * hinterlegen kann.<br>
+ * Zudem sollte eine {@code CaptionsChangeable}-Komponente den {@link #resetCaptions(Map)}-Aufruf
+ * an alle in ihr enthaltenen {@code CaptionsChangeable}-Komponenten weiterleiten.
+ * {@link CaptionsChangeablePanel} stellt ein ansonsten normales {@link JPanel}
+ * dar, welches diese Funktionalitaet bereits implementiert.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of
+ *   Bonn/Germany)
+ * @version 1.0
+ */
+public interface CaptionsChangeable {
+  /**
+   * Aktualisiert alle Beschriftungen der Komponente entsprechend der uebergebenen
+   * Map.
+   * @param captionMap enthaelt die neuen Beschriftungen
+   */
+  public void resetCaptions(Map<String, Object> captionMap);
+}

Modified: trunk/src/schmitzm/swing/CaptionsChangeablePanel.java
===================================================================
--- trunk/src/schmitzm/swing/CaptionsChangeablePanel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/CaptionsChangeablePanel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,103 +1,121 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing;
-
-import java.awt.Component;
-import java.awt.Container;
-import java.awt.FlowLayout;
-import java.awt.LayoutManager;
-import java.util.HashMap;
-import java.util.Map;
-
-/**
- * Diese Klasse stellt ein normales {@link JPanel} dar, welches
- * jedoch die {@link CaptionsChangeable}-Funktionaelitaet beim Aufruf von
- * {@link #resetCaptions(Map)} an alle im Panel enthaltenen
- * {@link CaptionsChangeable}-Komponenten weiterleitet.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class CaptionsChangeablePanel extends JPanel implements CaptionsChangeable {
-  /**
-   * Erzeugt ein neues Panel.
-   * @param layout Layout fuer das Panel
-   * @param isDoubleBuffered {@code true} fuer "double-buffering", welches zwar
-   *        zusaetzlichen Speicher benoetigt, aber schnelle und flicker-freie
-   *        Updates gewaehrleistet
-   */
-  public CaptionsChangeablePanel(LayoutManager layout, boolean isDoubleBuffered) {
-    super(layout, isDoubleBuffered);
-  }
-
-  /**
-   * Erzeugt ein gepuffertes Panel.
-   * @param layout Layout fuer das Panel
-   */
-  public CaptionsChangeablePanel(LayoutManager layout) {
-    super(layout);
-  }
-
-  /**
-   * Erzeugt ein {@link FlowLayout}-Panel.
-   * @param isDoubleBuffered {@code true} fuer "double-buffering", welches zwar
-   *        zusaetzlichen Speicher benoetigt, aber schnelle und flicker-freie
-   *        Updates gewaehrleistet
-   */
-  public CaptionsChangeablePanel(boolean isDoubleBuffered) {
-    super(isDoubleBuffered);
-  }
-
-  /**
-   * Erzeugt ein gepuffertes {@link FlowLayout}-Panel.
-   */
-  public CaptionsChangeablePanel() {
-    super();
-  }
-
-  /**
-   * Startet die Aktualisierung der Beschriftungen an alle im Panel
-   * enthaltenen {@link CaptionsChangeable}-Komponenten mit einer leeren
-   * {@link HashMap}.
-   */
-  public void resetCaptions() {
-    resetCaptions(new HashMap<String,Object>());
-  }
-
-  /**
-   * Leitet die Aktualisierung der Beschriftungen an alle im Panel
-   * enthaltenen {@link CaptionsChangeable}-Komponenten weiter.
-   * @param captionMap enthaelt die neuen Beschriftungen
-   */
-  public void resetCaptions(Map<String, Object> captionMap) {
-    resetCaptions(this,captionMap);
-  }
-
-  /**
-   * Leitet die Aktualisierung der Beschriftungen an alle im Container {@code container}
-   * enthaltenen {@link CaptionsChangeable}-Komponenten weiter.
-   * Zudem wird die Auswertung rekursiv fuer alle in {@code container} enthaltenen
-   * {@link Container} fortgefuehrt.
-   * @param container  ein Container der weitere {@link Component Components}
-   *                   enthaelt
-   * @param captionMap enthaelt die neuen Beschriftungen
-   */
-  public static void resetCaptions(Container container, Map<String, Object> captionMap) {
-    Component[] innerComponents = container.getComponents();
-    for (Component c : innerComponents) {
-      if (c instanceof CaptionsChangeable)
-        ( (CaptionsChangeable) c).resetCaptions(captionMap);
-      if (c instanceof Container)
-        resetCaptions((Container)c, captionMap);
-    }
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
+
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.FlowLayout;
+import java.awt.LayoutManager;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Diese Klasse stellt ein normales {@link JPanel} dar, welches
+ * jedoch die {@link CaptionsChangeable}-Funktionaelitaet beim Aufruf von
+ * {@link #resetCaptions(Map)} an alle im Panel enthaltenen
+ * {@link CaptionsChangeable}-Komponenten weiterleitet.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class CaptionsChangeablePanel extends JPanel implements CaptionsChangeable {
+  /**
+   * Erzeugt ein neues Panel.
+   * @param layout Layout fuer das Panel
+   * @param isDoubleBuffered {@code true} fuer "double-buffering", welches zwar
+   *        zusaetzlichen Speicher benoetigt, aber schnelle und flicker-freie
+   *        Updates gewaehrleistet
+   */
+  public CaptionsChangeablePanel(LayoutManager layout, boolean isDoubleBuffered) {
+    super(layout, isDoubleBuffered);
+  }
+
+  /**
+   * Erzeugt ein gepuffertes Panel.
+   * @param layout Layout fuer das Panel
+   */
+  public CaptionsChangeablePanel(LayoutManager layout) {
+    super(layout);
+  }
+
+  /**
+   * Erzeugt ein {@link FlowLayout}-Panel.
+   * @param isDoubleBuffered {@code true} fuer "double-buffering", welches zwar
+   *        zusaetzlichen Speicher benoetigt, aber schnelle und flicker-freie
+   *        Updates gewaehrleistet
+   */
+  public CaptionsChangeablePanel(boolean isDoubleBuffered) {
+    super(isDoubleBuffered);
+  }
+
+  /**
+   * Erzeugt ein gepuffertes {@link FlowLayout}-Panel.
+   */
+  public CaptionsChangeablePanel() {
+    super();
+  }
+
+  /**
+   * Startet die Aktualisierung der Beschriftungen an alle im Panel
+   * enthaltenen {@link CaptionsChangeable}-Komponenten mit einer leeren
+   * {@link HashMap}.
+   */
+  public void resetCaptions() {
+    resetCaptions(new HashMap<String,Object>());
+  }
+
+  /**
+   * Leitet die Aktualisierung der Beschriftungen an alle im Panel
+   * enthaltenen {@link CaptionsChangeable}-Komponenten weiter.
+   * @param captionMap enthaelt die neuen Beschriftungen
+   */
+  public void resetCaptions(Map<String, Object> captionMap) {
+    resetCaptions(this,captionMap);
+  }
+
+  /**
+   * Leitet die Aktualisierung der Beschriftungen an alle im Container {@code container}
+   * enthaltenen {@link CaptionsChangeable}-Komponenten weiter.
+   * Zudem wird die Auswertung rekursiv fuer alle in {@code container} enthaltenen
+   * {@link Container} fortgefuehrt.
+   * @param container  ein Container der weitere {@link Component Components}
+   *                   enthaelt
+   * @param captionMap enthaelt die neuen Beschriftungen
+   */
+  public static void resetCaptions(Container container, Map<String, Object> captionMap) {
+    Component[] innerComponents = container.getComponents();
+    for (Component c : innerComponents) {
+      if (c instanceof CaptionsChangeable)
+        ( (CaptionsChangeable) c).resetCaptions(captionMap);
+      if (c instanceof Container)
+        resetCaptions((Container)c, captionMap);
+    }
+  }
+
+}

Modified: trunk/src/schmitzm/swing/CircleIcon.java
===================================================================
--- trunk/src/schmitzm/swing/CircleIcon.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/CircleIcon.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,72 +1,90 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing;
-
 import java.awt.Color;
 import java.awt.Component;
 import java.awt.Graphics;
 
 import javax.swing.Icon;
-
-/**
- * Diese Klasse stellt ein Icon in Form eines ausgefuellten Kreises
- * dar.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class CircleIcon implements Icon
-{
-    private int   width;
-    private int   height;
-    private Color color;
-
-    /**
-     * Erzeugt ein Icon mit einem ausgefuellten Kreis.
-     * @param width Breite des Kreises
-     * @param height Hoehe des Kreises
-     * @param color Farbe des Kreises
-     */
-    public CircleIcon(int width, int height, Color color)
-    {
-        this.width  = width;
-        this.height = height;
-        this.color  = color;
-    }
-
-    /**
-     * Malt den Kreis an die angegeben Stelle (x,y) in das Graphics-
-     * Objekt.
-     */
-    public void paintIcon(Component c, Graphics g, int x, int y)
-    {
-        g.setColor(color);
-        g.fillOval(x,y,width,height);
-    }
-
-    /**
-     * Liefert die Hoehe des Kreises.
-     * @return Hoehe des Kreises in Pixeln
-     */
-    public int getIconHeight()
-    {
-        return height;
-    }
-
-    /**
-     * Liefert die Breite des Kreises.
-     * @return Breite des Kreises in Pixeln
-     */
-    public int getIconWidth()
-    {
-        return width;
-    }
-}
+
+/**
+ * Diese Klasse stellt ein Icon in Form eines ausgefuellten Kreises
+ * dar.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class CircleIcon implements Icon
+{
+    private int   width;
+    private int   height;
+    private Color color;
+
+    /**
+     * Erzeugt ein Icon mit einem ausgefuellten Kreis.
+     * @param width Breite des Kreises
+     * @param height Hoehe des Kreises
+     * @param color Farbe des Kreises
+     */
+    public CircleIcon(int width, int height, Color color)
+    {
+        this.width  = width;
+        this.height = height;
+        this.color  = color;
+    }
+
+    /**
+     * Malt den Kreis an die angegeben Stelle (x,y) in das Graphics-
+     * Objekt.
+     */
+    public void paintIcon(Component c, Graphics g, int x, int y)
+    {
+        g.setColor(color);
+        g.fillOval(x,y,width,height);
+    }
+
+    /**
+     * Liefert die Hoehe des Kreises.
+     * @return Hoehe des Kreises in Pixeln
+     */
+    public int getIconHeight()
+    {
+        return height;
+    }
+
+    /**
+     * Liefert die Breite des Kreises.
+     * @return Breite des Kreises in Pixeln
+     */
+    public int getIconWidth()
+    {
+        return width;
+    }
+}

Modified: trunk/src/schmitzm/swing/ColorInputOption.java
===================================================================
--- trunk/src/schmitzm/swing/ColorInputOption.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/ColorInputOption.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,16 +1,34 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing;
-
 import java.awt.Color;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
@@ -22,135 +40,135 @@
 import javax.swing.JComponent;
 import javax.swing.JDialog;
 import javax.swing.JLabel;
-
-/**
- * Diese Klasse stellt eine Farb-Eingabe-Option fuer das {@link MultipleOptionPane}
- * dar. Diese wird durch eine {@link JLabel} in der jeweiligen Farbe dargestellt.
- * Bei einem Klick auf das Label erscheint ein {@link JColorChooser}, ueber den
- * der Optionswert (Farbe) geaendert werden kann.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class ColorInputOption extends InputOption {
-  private   JColorChooser colorChooser;
-  private   JDialog       dialog;
-
-  /**
-   * Erzeugt eine neue Eingabe-Option.
-   * @param label     Beschreibung
-   * @param inpNeeded gibt an, ob eine Leer-Eingabe erlaubt ist
-   */
-  public ColorInputOption(String label, boolean inpNeeded) {
-    this(label,inpNeeded,null);
-  }
-
-  /**
-   * Erzeugt eine neue Eingabe-Option.
-   * @param label     Beschreibung
-   * @param inpNeeded gibt an, ob eine Leer-Eingabe erlaubt ist
-   * @param defColor  vorgeblendeter Optionswert
-   */
-  public ColorInputOption(String label, boolean inpNeeded, Color defColor) {
-    super(label, inpNeeded);
-    setValue( (defColor != null) ? defColor : new Color(0, 0, 0, 0));
-
-    // Dialog zum Farbe auswaehlen
-    colorChooser = new JColorChooser();
-    dialog = JColorChooser.createDialog(
-        this,
-        "Farbe auswaehlen",
-        true, //modal
-        colorChooser,
-        new ActionListener() { //OK button handler
-             public void actionPerformed(ActionEvent e) {
-                 // wird auf OK geklickt wird die ausgewaehlte Farbe
-                 // uebernommen
-                 setValue(colorChooser.getColor());
-               }
-             },
-        null // CANCEL button handler
-    );
-  }
-
-  /**
-   * Erzeugt eine neue Instanz von {@link JLabel}. Dieses ist transparent und
-   * schwart umrandet.<br>
-   * Bei einem Klick auf das Label oeffnet sich ein {@link JColorChooser}
-   * ueber den eine neue Farbe ausgewaehlt werden kann.
-   */
-  protected JComponent createInputComponent() {
-//    // Eigentlich sollte ein JLabel verwendet werden. Dieses nimmt aber
-//    // nicht automatisch die maximale Container-Breite des uebergeordneten
-//    // Containers (bei SpringLayout) an. Deshalb wird ein TextField "vergewaltigt".
-//    JTextField l = new JTextField("");
-//    l.setEditable(false);
-//    l.setBorder(null);
-    JLabel l = new JLabel(" ");
-    //////////////
-    l.setOpaque(true);
+
+/**
+ * Diese Klasse stellt eine Farb-Eingabe-Option fuer das {@link MultipleOptionPane}
+ * dar. Diese wird durch eine {@link JLabel} in der jeweiligen Farbe dargestellt.
+ * Bei einem Klick auf das Label erscheint ein {@link JColorChooser}, ueber den
+ * der Optionswert (Farbe) geaendert werden kann.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class ColorInputOption extends InputOption {
+  private   JColorChooser colorChooser;
+  private   JDialog       dialog;
+
+  /**
+   * Erzeugt eine neue Eingabe-Option.
+   * @param label     Beschreibung
+   * @param inpNeeded gibt an, ob eine Leer-Eingabe erlaubt ist
+   */
+  public ColorInputOption(String label, boolean inpNeeded) {
+    this(label,inpNeeded,null);
+  }
+
+  /**
+   * Erzeugt eine neue Eingabe-Option.
+   * @param label     Beschreibung
+   * @param inpNeeded gibt an, ob eine Leer-Eingabe erlaubt ist
+   * @param defColor  vorgeblendeter Optionswert
+   */
+  public ColorInputOption(String label, boolean inpNeeded, Color defColor) {
+    super(label, inpNeeded);
+    setValue( (defColor != null) ? defColor : new Color(0, 0, 0, 0));
+
+    // Dialog zum Farbe auswaehlen
+    colorChooser = new JColorChooser();
+    dialog = JColorChooser.createDialog(
+        this,
+        "Farbe auswaehlen",
+        true, //modal
+        colorChooser,
+        new ActionListener() { //OK button handler
+             public void actionPerformed(ActionEvent e) {
+                 // wird auf OK geklickt wird die ausgewaehlte Farbe
+                 // uebernommen
+                 setValue(colorChooser.getColor());
+               }
+             },
+        null // CANCEL button handler
+    );
+  }
+
+  /**
+   * Erzeugt eine neue Instanz von {@link JLabel}. Dieses ist transparent und
+   * schwart umrandet.<br>
+   * Bei einem Klick auf das Label oeffnet sich ein {@link JColorChooser}
+   * ueber den eine neue Farbe ausgewaehlt werden kann.
+   */
+  protected JComponent createInputComponent() {
+//    // Eigentlich sollte ein JLabel verwendet werden. Dieses nimmt aber
+//    // nicht automatisch die maximale Container-Breite des uebergeordneten
+//    // Containers (bei SpringLayout) an. Deshalb wird ein TextField "vergewaltigt".
+//    JTextField l = new JTextField("");
+//    l.setEditable(false);
+//    l.setBorder(null);
+    JLabel l = new JLabel(" ");
+    //////////////
+    l.setOpaque(true);
     //l.setBorder(BorderFactory.createLineBorder(Color.BLACK));
     l.setBorder(BorderFactory.createRaisedBevelBorder());
     //l.setBorder(BorderFactory.createLoweredBevelBorder());
 
-    // Beim Klick auf das Label erscheint der Auswahl-Dialog
-    // fuer die Farben
-    l.addMouseListener( new MouseAdapter() {
-      public void mouseClicked(MouseEvent e) {
-        if ( e.getButton() == MouseEvent.BUTTON1 ) {
-          colorChooser.setColor( inpComp.getBackground() );
-          dialog.setVisible(true);
-        }
-      }
-    });
-    return l;
-  }
-
-  /**
-   * Liefert den Wert, der in der Option eingegeben wurde. Prueft zuerst
-   * auf Gueltigkeit und ruft dann {@link #performGetValue()} auf.
-   * @return <code>null</code> wenn die aktuelle Eingabe nicht zulaessig ist
-   *         (siehe {@link #isInputValid()})
-   */
-  public Color getValue() {
-    return (Color)super.getValue();
-  }
-
-  /**
-   * Liefert immer <code>true</code>, da keine speziellen Anforderungen
-   * an die Farb-Eingabe gestellt werden.
-   */
-  protected boolean performIsInputValid() {
-    return true;
-  }
-
-  /**
-   * Liefert immer <code>true</code>, wenn keine Farbe (<code>null</code>)
-   * ausgewaehlt ist.
-   */
-  protected boolean performIsInputEmpty() {
-    return inpComp.getBackground() == null;
-  }
-
-  /**
-   * Liefert die aktuell in der Option ausgewaehlte Farbe.
-   */
-  protected Color performGetValue() {
-    return inpComp.getBackground();
-  }
-
-  /**
-   * Setzt den Wert der Farb-Option.
-   * @param newValue neue Farbe (muss eine {@link Color}-Instanz sein)
-   * @return <code>false</code> falls keine {@link Color} uebergeben wird.
-   */
-  protected boolean performSetValue(Object newValue) {
-    if ( !(newValue instanceof Color) )
-      return false;
-    Color color = (Color)newValue;
-    this.inpComp.setBackground(color);
-    this.inpComp.setToolTipText("RGB value: " + color.getRed() + ", "
-                                              + color.getGreen() + ", "
-                                              + color.getBlue());
-    return true;
-  }
-}
+    // Beim Klick auf das Label erscheint der Auswahl-Dialog
+    // fuer die Farben
+    l.addMouseListener( new MouseAdapter() {
+      public void mouseClicked(MouseEvent e) {
+        if ( e.getButton() == MouseEvent.BUTTON1 ) {
+          colorChooser.setColor( inpComp.getBackground() );
+          dialog.setVisible(true);
+        }
+      }
+    });
+    return l;
+  }
+
+  /**
+   * Liefert den Wert, der in der Option eingegeben wurde. Prueft zuerst
+   * auf Gueltigkeit und ruft dann {@link #performGetValue()} auf.
+   * @return <code>null</code> wenn die aktuelle Eingabe nicht zulaessig ist
+   *         (siehe {@link #isInputValid()})
+   */
+  public Color getValue() {
+    return (Color)super.getValue();
+  }
+
+  /**
+   * Liefert immer <code>true</code>, da keine speziellen Anforderungen
+   * an die Farb-Eingabe gestellt werden.
+   */
+  protected boolean performIsInputValid() {
+    return true;
+  }
+
+  /**
+   * Liefert immer <code>true</code>, wenn keine Farbe (<code>null</code>)
+   * ausgewaehlt ist.
+   */
+  protected boolean performIsInputEmpty() {
+    return inpComp.getBackground() == null;
+  }
+
+  /**
+   * Liefert die aktuell in der Option ausgewaehlte Farbe.
+   */
+  protected Color performGetValue() {
+    return inpComp.getBackground();
+  }
+
+  /**
+   * Setzt den Wert der Farb-Option.
+   * @param newValue neue Farbe (muss eine {@link Color}-Instanz sein)
+   * @return <code>false</code> falls keine {@link Color} uebergeben wird.
+   */
+  protected boolean performSetValue(Object newValue) {
+    if ( !(newValue instanceof Color) )
+      return false;
+    Color color = (Color)newValue;
+    this.inpComp.setBackground(color);
+    this.inpComp.setToolTipText("RGB value: " + color.getRed() + ", "
+                                              + color.getGreen() + ", "
+                                              + color.getBlue());
+    return true;
+  }
+}

Modified: trunk/src/schmitzm/swing/Compass.java
===================================================================
--- trunk/src/schmitzm/swing/Compass.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/Compass.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,213 +1,231 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing;
-
-import java.awt.BorderLayout;
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.Graphics2D;
-import java.awt.event.MouseListener;
-import java.awt.geom.Point2D;
-import java.awt.geom.Rectangle2D;
-
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-
-import org.jfree.chart.ChartPanel;
-import org.jfree.chart.JFreeChart;
-import org.jfree.chart.plot.CompassPlot;
-import org.jfree.chart.plot.PlotRenderingInfo;
-import org.jfree.chart.plot.PlotState;
-import org.jfree.data.general.DefaultValueDataset;
-import org.jfree.data.general.ValueDataset;
-
-/**
- * Diese Komponente stellt eine Kompass-Nadel dar, deren Ausrichtung ueber
- * eine Grad-Angabe zwischen 0° und 360° (Nord = 0°; West = 90°) eingestellt wird.
- * {@link MouseListener} oder aehnliches koennen aus technischen Gruenden
- * nicht der Komponente direkt zugewiesen werden, sondern muessen dem
- * {@linkplain #getCompassPane() Content-Pane} zugewiesen werden.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public  class Compass extends JPanel {
-  /** Ereignis, welches an die Listener gesendet wird, wenn sich der Kompass-Wert
-   *  aendert. */
-  protected ChangeEvent changeEvent = new ChangeEvent(this);
-
-  private ChartPanel chartPanel;
-  private double degree = 0;
-
-  /**
-   * Erzeugt eine neue Kompass-Komponente.
-   */
-  public Compass() {
-    this(0);
-  }
-
-  /**
-   * Erzeugt eine neue Kompass-Komponente.
-   * @param degree angezeigte Grad-Angabe (Nord = 0°, West = 90°)
-   */
-  public Compass(double degree) {
-    super();
-    setLayout( new BorderLayout() );
-    chartPanel = new ChartPanel(
-      null,      // Chart
-      100,       // Width
-      100,       // Height
-      0,         // Min. draw width
-      0,         // Min. draw height
-      9999999,   // Max. draw width
-      9999999,   // Max. draw height
-      true,      // Use buffer
-      true,     // Properties
-      false,     // Save
-      false,     // Print
-      false,     // Zoom
-      false      // Tooltips
-    );
-    setValue(degree);
-    this.add(chartPanel,BorderLayout.CENTER);
-  }
-
-  /**
-   * Setzt die Hintergrund-Farbe (auch fuer alle Unterkomponenten).
-   * @param bgColor Hintergrund-Farbe
-   */
-  public void setBackground(Color bgColor) {
-    setBackground(bgColor, true);
-    if ( chartPanel != null && chartPanel.getChart() != null )
-      chartPanel.getChart().setBackgroundPaint( bgColor );
-  }
-
-  /**
-   * Liefert die Komponente des Kompass fuer {@link MouseListener} oder aehnliches.
-   */
-  public Component getCompassPane() {
-    return chartPanel;
-  }
-
-  /**
-   * Setzt die angezeigte Grad-Angabe und erzeugt ein {@link ChangeEvent} fuer
-   * alle angeschlossenen {@link ChangeListener}.
-   * @param degree angezeigte Grad-Angabe (Nord = 0°, West = 90°)
-   */
-  public void setValue(double degree) {
-    double oldDegree = this.degree;
-    this.degree = degree % 360; // auf ]-360,+360[ normieren
-    this.degree = (this.degree+360) % 360; // auf [0,360[ normierern
-    chartPanel.setChart( createCompassChart( this.degree ) );
-    if (this.degree != oldDegree)
-      fireStateChanged();
-  }
-
-  /**
-   * Liefert die angezeigte Grad-Angabe aus [0°,360°[.
-   */
-  public double getValue() {
-    return degree;
-  }
-
-  /**
-   * Fuegt dem Kompass einen {@link ChangeListener} hinzu. Dieser wird jedesmal
-   * informtiert, wenn sich der Wert des Kompass aendert.
-   * @param listener neuer {@link ChangeListener}
-   */
-  public void addChangeListener(ChangeListener listener) {
-    this.listenerList.add( ChangeListener.class, listener );
-  }
-
-  /**
-   * Entfernt einen {@link ChangeListener} vom Kompass.
-   * @param listener zu entfernender {@link ChangeListener}
-   */
-  public void removeChangeListener(ChangeListener listener) {
-    this.listenerList.remove( ChangeListener.class, listener );
-  }
-
-  /**
-   * Liefert die Anzahl der an den Kompass angeschlossenen {@link ChangeListener}.
-   */
-  public int getListenerCount() {
-    return listenerList.getListenerCount(ChangeListener.class);
-  }
-
-  /**
-   * Liefert an den Kompass angeschlossenen {@link ChangeListener}.
-   */
-  public ChangeListener[] getChangeListeners() {
-    return listenerList.getListeners(ChangeListener.class);
-  }
-
-  /**
-   * Leitet ein {@link ChangeEvent} an alle angeschlossenen {@link ChangeListener}.
-   * @see #addChangeListener(ChangeListener)
-   * @see #removeChangeListener(ChangeListener)
-   */
-  protected void fireStateChanged() {
-    ChangeListener[] listeners = getChangeListeners();
-    for (ChangeListener l : listeners)
-      l.stateChanged(changeEvent);
-  }
-
-//  public void setPreferredSize(Dimension d) {
-//    int min = Math.min(d.height,d.width);
-//    chartPanel.setPreferredSize( new Dimension(min,min) );
-//    super.setPreferredSize(d);
-//  }
-//
-//  public void setSize(Dimension d) {
-//    int min = Math.min(d.height,d.width);
-//    chartPanel.setPreferredSize( new Dimension(min,min) );
-//    super.setSize(d);
-//  }
-//
-//  public void setSize(int w, int h) {
-//    int min = Math.min(w,h);
-//    chartPanel.setSize( new Dimension(min,min) );
-//    super.setSize(w,h);
-//  }
-
-  /**
-   * Erzeugt ein Chart in Form einer Kompass-Nadel.
-   * @param degree angezeigte Grad-Angabe (Nord = 0°, West = 90°)
-   */
-  private JFreeChart createCompassChart(double degree) {
-    // Bei der Chart-Komponente ist Ost = 90°
-    ValueDataset dataset = new DefaultValueDataset(-degree);
-    CompassPlot plot = new CompassPlot(dataset) {
-      public void draw(Graphics2D g, Rectangle2D area, Point2D anchor, PlotState parentState, PlotRenderingInfo info) {
-//        System.out.println( area + "     " + g.getClipBounds() + "   " + g.getTransform().getScaleX() + "  " + g.getTransform().getScaleY());
-//        double minSize  = Math.min(area.getWidth(), area.getHeight());
-//        double minScale = Math.min(g.getTransform().getScaleX(), g.getTransform().getScaleY() );
-//        double x        = (chartPanel.getWidth()-minSize)/2;
-//        double y        = (chartPanel.getHeight()-minSize)/2;
-//        area.setFrame( x, y, minSize, minSize);
-//        g.setTransform( AffineTransform.getScaleInstance(minScale,minScale) );
-//        System.out.println( area + "     " + g.getClipBounds() + "   " + g.getTransform().getScaleX() + "  " + g.getTransform().getScaleY());
-//        System.out.println();
-        super.draw(g,area,anchor,parentState,info);
-      }
-    };
-    plot.setSeriesNeedle(4);
-    plot.setSeriesPaint(0, Color.black);
-    plot.setSeriesOutlinePaint(0, Color.black);
-    plot.setRosePaint(Color.red);
-    plot.setRoseHighlightPaint(Color.gray);
-    plot.setRoseCenterPaint(Color.white);
-    plot.setDrawBorder(false);
-    JFreeChart chart = new JFreeChart(plot);
-    chart.setBackgroundPaint( getBackground() );
-    return chart;
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Graphics2D;
+import java.awt.event.MouseListener;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+import org.jfree.chart.ChartPanel;
+import org.jfree.chart.JFreeChart;
+import org.jfree.chart.plot.CompassPlot;
+import org.jfree.chart.plot.PlotRenderingInfo;
+import org.jfree.chart.plot.PlotState;
+import org.jfree.data.general.DefaultValueDataset;
+import org.jfree.data.general.ValueDataset;
+
+/**
+ * Diese Komponente stellt eine Kompass-Nadel dar, deren Ausrichtung ueber
+ * eine Grad-Angabe zwischen 0° und 360° (Nord = 0°; West = 90°) eingestellt wird.
+ * {@link MouseListener} oder aehnliches koennen aus technischen Gruenden
+ * nicht der Komponente direkt zugewiesen werden, sondern muessen dem
+ * {@linkplain #getCompassPane() Content-Pane} zugewiesen werden.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public  class Compass extends JPanel {
+  /** Ereignis, welches an die Listener gesendet wird, wenn sich der Kompass-Wert
+   *  aendert. */
+  protected ChangeEvent changeEvent = new ChangeEvent(this);
+
+  private ChartPanel chartPanel;
+  private double degree = 0;
+
+  /**
+   * Erzeugt eine neue Kompass-Komponente.
+   */
+  public Compass() {
+    this(0);
+  }
+
+  /**
+   * Erzeugt eine neue Kompass-Komponente.
+   * @param degree angezeigte Grad-Angabe (Nord = 0°, West = 90°)
+   */
+  public Compass(double degree) {
+    super();
+    setLayout( new BorderLayout() );
+    chartPanel = new ChartPanel(
+      null,      // Chart
+      100,       // Width
+      100,       // Height
+      0,         // Min. draw width
+      0,         // Min. draw height
+      9999999,   // Max. draw width
+      9999999,   // Max. draw height
+      true,      // Use buffer
+      true,     // Properties
+      false,     // Save
+      false,     // Print
+      false,     // Zoom
+      false      // Tooltips
+    );
+    setValue(degree);
+    this.add(chartPanel,BorderLayout.CENTER);
+  }
+
+  /**
+   * Setzt die Hintergrund-Farbe (auch fuer alle Unterkomponenten).
+   * @param bgColor Hintergrund-Farbe
+   */
+  public void setBackground(Color bgColor) {
+    setBackground(bgColor, true);
+    if ( chartPanel != null && chartPanel.getChart() != null )
+      chartPanel.getChart().setBackgroundPaint( bgColor );
+  }
+
+  /**
+   * Liefert die Komponente des Kompass fuer {@link MouseListener} oder aehnliches.
+   */
+  public Component getCompassPane() {
+    return chartPanel;
+  }
+
+  /**
+   * Setzt die angezeigte Grad-Angabe und erzeugt ein {@link ChangeEvent} fuer
+   * alle angeschlossenen {@link ChangeListener}.
+   * @param degree angezeigte Grad-Angabe (Nord = 0°, West = 90°)
+   */
+  public void setValue(double degree) {
+    double oldDegree = this.degree;
+    this.degree = degree % 360; // auf ]-360,+360[ normieren
+    this.degree = (this.degree+360) % 360; // auf [0,360[ normierern
+    chartPanel.setChart( createCompassChart( this.degree ) );
+    if (this.degree != oldDegree)
+      fireStateChanged();
+  }
+
+  /**
+   * Liefert die angezeigte Grad-Angabe aus [0°,360°[.
+   */
+  public double getValue() {
+    return degree;
+  }
+
+  /**
+   * Fuegt dem Kompass einen {@link ChangeListener} hinzu. Dieser wird jedesmal
+   * informtiert, wenn sich der Wert des Kompass aendert.
+   * @param listener neuer {@link ChangeListener}
+   */
+  public void addChangeListener(ChangeListener listener) {
+    this.listenerList.add( ChangeListener.class, listener );
+  }
+
+  /**
+   * Entfernt einen {@link ChangeListener} vom Kompass.
+   * @param listener zu entfernender {@link ChangeListener}
+   */
+  public void removeChangeListener(ChangeListener listener) {
+    this.listenerList.remove( ChangeListener.class, listener );
+  }
+
+  /**
+   * Liefert die Anzahl der an den Kompass angeschlossenen {@link ChangeListener}.
+   */
+  public int getListenerCount() {
+    return listenerList.getListenerCount(ChangeListener.class);
+  }
+
+  /**
+   * Liefert an den Kompass angeschlossenen {@link ChangeListener}.
+   */
+  public ChangeListener[] getChangeListeners() {
+    return listenerList.getListeners(ChangeListener.class);
+  }
+
+  /**
+   * Leitet ein {@link ChangeEvent} an alle angeschlossenen {@link ChangeListener}.
+   * @see #addChangeListener(ChangeListener)
+   * @see #removeChangeListener(ChangeListener)
+   */
+  protected void fireStateChanged() {
+    ChangeListener[] listeners = getChangeListeners();
+    for (ChangeListener l : listeners)
+      l.stateChanged(changeEvent);
+  }
+
+//  public void setPreferredSize(Dimension d) {
+//    int min = Math.min(d.height,d.width);
+//    chartPanel.setPreferredSize( new Dimension(min,min) );
+//    super.setPreferredSize(d);
+//  }
+//
+//  public void setSize(Dimension d) {
+//    int min = Math.min(d.height,d.width);
+//    chartPanel.setPreferredSize( new Dimension(min,min) );
+//    super.setSize(d);
+//  }
+//
+//  public void setSize(int w, int h) {
+//    int min = Math.min(w,h);
+//    chartPanel.setSize( new Dimension(min,min) );
+//    super.setSize(w,h);
+//  }
+
+  /**
+   * Erzeugt ein Chart in Form einer Kompass-Nadel.
+   * @param degree angezeigte Grad-Angabe (Nord = 0°, West = 90°)
+   */
+  private JFreeChart createCompassChart(double degree) {
+    // Bei der Chart-Komponente ist Ost = 90°
+    ValueDataset dataset = new DefaultValueDataset(-degree);
+    CompassPlot plot = new CompassPlot(dataset) {
+      public void draw(Graphics2D g, Rectangle2D area, Point2D anchor, PlotState parentState, PlotRenderingInfo info) {
+//        System.out.println( area + "     " + g.getClipBounds() + "   " + g.getTransform().getScaleX() + "  " + g.getTransform().getScaleY());
+//        double minSize  = Math.min(area.getWidth(), area.getHeight());
+//        double minScale = Math.min(g.getTransform().getScaleX(), g.getTransform().getScaleY() );
+//        double x        = (chartPanel.getWidth()-minSize)/2;
+//        double y        = (chartPanel.getHeight()-minSize)/2;
+//        area.setFrame( x, y, minSize, minSize);
+//        g.setTransform( AffineTransform.getScaleInstance(minScale,minScale) );
+//        System.out.println( area + "     " + g.getClipBounds() + "   " + g.getTransform().getScaleX() + "  " + g.getTransform().getScaleY());
+//        System.out.println();
+        super.draw(g,area,anchor,parentState,info);
+      }
+    };
+    plot.setSeriesNeedle(4);
+    plot.setSeriesPaint(0, Color.black);
+    plot.setSeriesOutlinePaint(0, Color.black);
+    plot.setRosePaint(Color.red);
+    plot.setRoseHighlightPaint(Color.gray);
+    plot.setRoseCenterPaint(Color.white);
+    plot.setDrawBorder(false);
+    JFreeChart chart = new JFreeChart(plot);
+    chart.setBackgroundPaint( getBackground() );
+    return chart;
+  }
+}

Modified: trunk/src/schmitzm/swing/ExceptionDialog.java
===================================================================
--- trunk/src/schmitzm/swing/ExceptionDialog.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/ExceptionDialog.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,240 +1,258 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing;
-
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.Frame;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-
-import javax.swing.JButton;
-import javax.swing.JDialog;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JScrollPane;
-import javax.swing.JTextArea;
-import javax.swing.JToggleButton;
-
-/**
- * Diese Klasse stellt eine modale Fehler-Meldung dar. Diese besteht neben
- * einer Meldung aus einem Text-Feld, in dem der StackTrace des Fehlers
- * angezeigt wird.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class ExceptionDialog extends JDialog {
-  /** Speichert den angezeigten Fehler. */
-  protected Throwable err = null;
-  /** Label in dem die Meldung angezeigt wird. */
-  protected JLabel  messageLabel = null;
-  /** Button um den Dialog zu schliessen. */
-  protected JButton okButton = null;
-  /** Button um Details anzuzeigen. */
-  protected JToggleButton detailsButton = null;
-  /** Bereich, in dem die Details angezeigt werden. */
-  protected JTextArea detailsTextArea = null;
-  /** ScrollPane, in dem sich die TextArea fuer die Details befinden. */
-  protected JScrollPane detailsScrollPane = null;
-  /** Verbindung zwischen StackTrace-PrintStream und TextArea*/
-  private TextAreaPrintStream detailsPrintStream= null;
-
-  /**
-   * Erzeugt einen neuen Fehler-Dialog. Dem Dialog wird zunaechst noch keine
-   * Fehlermeldung zugeordnet.
-   * @param parent   uebergeordnetes Fenster (kann <code>null</code> sein!)
-   * @see #setError(Throwable)
-   */
-  public ExceptionDialog(Component parent) {
-    this(parent,null,null,null);
-  }
-
-  /**
-   * Erzeugt einen neuen Fehler-Dialog. Der Dialog wird relativ zum Parent-Fenster
-   * zentriert.
-   * @param parent   uebergeordnetes Fenster (kann <code>null</code> sein!)
-   * @param err      darzustellender Fehler
-   */
-  public ExceptionDialog(Component parent, Throwable err) {
-    this(parent,err,null,null);
-  }
-
-  /**
-   * Erzeugt einen neuen Fehler-Dialog. Der Dialog wird relativ zum Parent-Fenster
-   * zentriert.
-   * @param parent     uebergeordnetes Fenster (kann <code>null</code> sein!)
-   * @param err        darzustellender Fehler
-   * @param title      Titel fuer das Fenster (kann <code>null</code> sein!)
-   * @param errMessage Meldung, die zu dem Fehler angezeigt angezeigt wird
-   *                   (kann <code>null</code> sein!)
-   */
-  public ExceptionDialog(Component parent, Throwable err, String title, String errMessage) {
-    this(parent,err,title,errMessage,false);
-  }
-  
-  /**
-   * Erzeugt einen neuen Fehler-Dialog. Der Dialog wird relativ zum Parent-Fenster
-   * zentriert.
-   * @param parent     uebergeordnetes Fenster (kann <code>null</code> sein!)
-   * @param err        darzustellender Fehler
-   * @param title      Titel fuer das Fenster (kann <code>null</code> sein!)
-   * @param errMessage Meldung, die zu dem Fehler angezeigt angezeigt wird
-   *                   (kann <code>null</code> sein!)
-   * @param showDetails wenn {@code true} werden die Details initial angezeigt
-   */
-  public ExceptionDialog(Component parent, Throwable err, String title, String errMessage, boolean showDetails) {
-    super((Frame)null,true);
-    if ( err != null && (title==null || title.trim().equals("")) )
-      title = err.getClass().getSimpleName();
-    if ( err != null && (errMessage==null || errMessage.trim().equals("")) )
-      errMessage = err.getMessage();
-
-    // Vorlagen-Dialog erzeugen
-    this.err               = err;
-    this.messageLabel      = new JLabel(errMessage);
-    this.okButton          = new JButton( SwingUtil.RESOURCE.getString("Ok") );
-    this.detailsButton     = new JToggleButton( SwingUtil.RESOURCE.getString("Details"), showDetails );
-    this.detailsTextArea   = new JTextArea(10,60);
-    this.detailsTextArea.setEditable(false);
-    this.detailsPrintStream = new TextAreaPrintStream(detailsTextArea);
-    this.detailsScrollPane  = new JScrollPane(detailsTextArea);
-    this.detailsScrollPane.setVisible(showDetails);
-    this.setError(err);
-    JOptionPane  pane = new JOptionPane(
-      messageLabel,
-      JOptionPane.ERROR_MESSAGE,
-      JOptionPane.DEFAULT_OPTION,
-      null,
-      new Object[] {okButton, detailsButton}
-    );
-    JDialog dialog = pane.createDialog(parent,title);
-
-    // Dialog nach Vorlage initialisieren
-    this.setTitle( dialog.getTitle() );
-    this.setAlwaysOnTop(true); // Fehler soll auch oberhalb von "alwaysOnTop"-
-                               // Komponenten erscheinen
-    this.getContentPane().setLayout(new BorderLayout());
-    this.getContentPane().add(dialog.getContentPane(), BorderLayout.NORTH);
-    this.getContentPane().add(detailsScrollPane, BorderLayout.CENTER);
-//    this.setDefaultCloseOperation( DO_NOTHING_ON_CLOSE );
-    this.okButton.addActionListener( new ActionListener() {
-      public void actionPerformed(ActionEvent e) {
-        setVisible(false);
-      }
-    } );
-    this.detailsButton.addActionListener( new ActionListener() {
-      public void actionPerformed(ActionEvent e) {
-        detailsScrollPane.setVisible( detailsButton.isSelected() );
-        pack();
-      }
-    } );
-
-    pack();
-    SwingUtil.setRelativeFramePosition(this,SwingUtil.getParentWindow(parent),0.5,0.5);
-  }
-
-  /**
-   * Liefert die angezeigte Fehlermeldung.
-   */
-  public String getMessage() {
-    return  messageLabel.getText();
-  }
-
-  /**
-   * Setzt die anzuzeigende Fehlermeldung.
-   */
-  public void setMessage(String mess) {
-    if ( mess == null || mess.trim().equals("") )
-      mess = getError() != null ? getError().getMessage() : SwingUtil.RESOURCE.getString("Error");
-    messageLabel.setText(mess);
-  }
-
-  /**
-   * Liefert den angezeigten Fehler.
-   */
-  public Throwable getError() {
-    return err;
-  }
-
-  /**
-   * Setzt den angezeigten Fehler.
-   */
-  public void setError(Throwable err) {
-    this.err = err;
-    if ( err == null )
-      detailsTextArea.setText("");
-    else
-      err.printStackTrace(detailsPrintStream);
-    detailsTextArea.select(0,0);
-  }
-
-  /**
-   * Zeigt einen Fehler-Dialog an.
-   * @param parent      uebergeordnetes Fenster (kann <code>null</code> sein!)
-   * @param err         darzustellender Fehler
-   * @param title       Titel fuer das Fenster (kann <code>null</code> sein!)
-   * @param errMessage  Meldung, die zu dem Fehler angezeigt angezeigt wird
-   *                    (kann <code>null</code> sein!)
-   */
-  public static void show(Component parent, Throwable err, String title, String errMessage) {
-    new ExceptionDialog(parent,err,title,errMessage).setVisible(true);
-  }
-
-  /**
-   * Zeigt einen Fehler-Dialog an.
-   * @param parent   uebergeordnetes Fenster (kann <code>null</code> sein!)
-   * @param err      darzustellender Fehler
-   */
-  public static void show(Component parent, Throwable err) {
-    new ExceptionDialog(parent,err).setVisible(true);
-  }
-
-  /**
-   * Zeigt einen Fehler-Dialog an.
-   * @param err darzustellender Fehler
-   */
-  public static void show(Throwable err) {
-    new ExceptionDialog(null,err).setVisible(true);
-  }
-
-  /**
-   * Zeigt einen Fehler-Dialog an.
-   * @param parent      uebergeordnetes Fenster (kann <code>null</code> sein!)
-   * @param err         darzustellender Fehler
-   * @param title       Titel fuer das Fenster (kann <code>null</code> sein!)
-   * @param errMessage  Meldung, die zu dem Fehler angezeigt angezeigt wird
-   *                    (kann <code>null</code> sein!)
-   * @param showDetails wenn {@code true} werden die Details initial angezeigt
-   */
-  public static void show(Component parent, Throwable err, String title, String errMessage, boolean showDetails) {
-    new ExceptionDialog(parent,err,title,errMessage,showDetails).setVisible(true);
-  }
-
-  /**
-   * Zeigt einen Fehler-Dialog an.
-   * @param parent   uebergeordnetes Fenster (kann <code>null</code> sein!)
-   * @param err      darzustellender Fehler
-   * @param showDetails wenn {@code true} werden die Details initial angezeigt
-   */
-  public static void show(Component parent, Throwable err, boolean showDetails) {
-    show(parent,err,null,null,showDetails);
-  }
-
-  /**
-   * Zeigt einen Fehler-Dialog an.
-   * @param err darzustellender Fehler
-   * @param showDetails wenn {@code true} werden die Details initial angezeigt
-   */
-  public static void show(Throwable err, boolean showDetails) {
-    show(null,err,showDetails);
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Frame;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JScrollPane;
+import javax.swing.JTextArea;
+import javax.swing.JToggleButton;
+
+/**
+ * Diese Klasse stellt eine modale Fehler-Meldung dar. Diese besteht neben
+ * einer Meldung aus einem Text-Feld, in dem der StackTrace des Fehlers
+ * angezeigt wird.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class ExceptionDialog extends JDialog {
+  /** Speichert den angezeigten Fehler. */
+  protected Throwable err = null;
+  /** Label in dem die Meldung angezeigt wird. */
+  protected JLabel  messageLabel = null;
+  /** Button um den Dialog zu schliessen. */
+  protected JButton okButton = null;
+  /** Button um Details anzuzeigen. */
+  protected JToggleButton detailsButton = null;
+  /** Bereich, in dem die Details angezeigt werden. */
+  protected JTextArea detailsTextArea = null;
+  /** ScrollPane, in dem sich die TextArea fuer die Details befinden. */
+  protected JScrollPane detailsScrollPane = null;
+  /** Verbindung zwischen StackTrace-PrintStream und TextArea*/
+  private TextAreaPrintStream detailsPrintStream= null;
+
+  /**
+   * Erzeugt einen neuen Fehler-Dialog. Dem Dialog wird zunaechst noch keine
+   * Fehlermeldung zugeordnet.
+   * @param parent   uebergeordnetes Fenster (kann <code>null</code> sein!)
+   * @see #setError(Throwable)
+   */
+  public ExceptionDialog(Component parent) {
+    this(parent,null,null,null);
+  }
+
+  /**
+   * Erzeugt einen neuen Fehler-Dialog. Der Dialog wird relativ zum Parent-Fenster
+   * zentriert.
+   * @param parent   uebergeordnetes Fenster (kann <code>null</code> sein!)
+   * @param err      darzustellender Fehler
+   */
+  public ExceptionDialog(Component parent, Throwable err) {
+    this(parent,err,null,null);
+  }
+
+  /**
+   * Erzeugt einen neuen Fehler-Dialog. Der Dialog wird relativ zum Parent-Fenster
+   * zentriert.
+   * @param parent     uebergeordnetes Fenster (kann <code>null</code> sein!)
+   * @param err        darzustellender Fehler
+   * @param title      Titel fuer das Fenster (kann <code>null</code> sein!)
+   * @param errMessage Meldung, die zu dem Fehler angezeigt angezeigt wird
+   *                   (kann <code>null</code> sein!)
+   */
+  public ExceptionDialog(Component parent, Throwable err, String title, String errMessage) {
+    this(parent,err,title,errMessage,false);
+  }
+  
+  /**
+   * Erzeugt einen neuen Fehler-Dialog. Der Dialog wird relativ zum Parent-Fenster
+   * zentriert.
+   * @param parent     uebergeordnetes Fenster (kann <code>null</code> sein!)
+   * @param err        darzustellender Fehler
+   * @param title      Titel fuer das Fenster (kann <code>null</code> sein!)
+   * @param errMessage Meldung, die zu dem Fehler angezeigt angezeigt wird
+   *                   (kann <code>null</code> sein!)
+   * @param showDetails wenn {@code true} werden die Details initial angezeigt
+   */
+  public ExceptionDialog(Component parent, Throwable err, String title, String errMessage, boolean showDetails) {
+    super((Frame)null,true);
+    if ( err != null && (title==null || title.trim().equals("")) )
+      title = err.getClass().getSimpleName();
+    if ( err != null && (errMessage==null || errMessage.trim().equals("")) )
+      errMessage = err.getMessage();
+
+    // Vorlagen-Dialog erzeugen
+    this.err               = err;
+    this.messageLabel      = new JLabel(errMessage);
+    this.okButton          = new JButton( SwingUtil.RESOURCE.getString("Ok") );
+    this.detailsButton     = new JToggleButton( SwingUtil.RESOURCE.getString("Details"), showDetails );
+    this.detailsTextArea   = new JTextArea(10,60);
+    this.detailsTextArea.setEditable(false);
+    this.detailsPrintStream = new TextAreaPrintStream(detailsTextArea);
+    this.detailsScrollPane  = new JScrollPane(detailsTextArea);
+    this.detailsScrollPane.setVisible(showDetails);
+    this.setError(err);
+    JOptionPane  pane = new JOptionPane(
+      messageLabel,
+      JOptionPane.ERROR_MESSAGE,
+      JOptionPane.DEFAULT_OPTION,
+      null,
+      new Object[] {okButton, detailsButton}
+    );
+    JDialog dialog = pane.createDialog(parent,title);
+
+    // Dialog nach Vorlage initialisieren
+    this.setTitle( dialog.getTitle() );
+    this.setAlwaysOnTop(true); // Fehler soll auch oberhalb von "alwaysOnTop"-
+                               // Komponenten erscheinen
+    this.getContentPane().setLayout(new BorderLayout());
+    this.getContentPane().add(dialog.getContentPane(), BorderLayout.NORTH);
+    this.getContentPane().add(detailsScrollPane, BorderLayout.CENTER);
+//    this.setDefaultCloseOperation( DO_NOTHING_ON_CLOSE );
+    this.okButton.addActionListener( new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        setVisible(false);
+      }
+    } );
+    this.detailsButton.addActionListener( new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        detailsScrollPane.setVisible( detailsButton.isSelected() );
+        pack();
+      }
+    } );
+
+    pack();
+    SwingUtil.setRelativeFramePosition(this,SwingUtil.getParentWindow(parent),0.5,0.5);
+  }
+
+  /**
+   * Liefert die angezeigte Fehlermeldung.
+   */
+  public String getMessage() {
+    return  messageLabel.getText();
+  }
+
+  /**
+   * Setzt die anzuzeigende Fehlermeldung.
+   */
+  public void setMessage(String mess) {
+    if ( mess == null || mess.trim().equals("") )
+      mess = getError() != null ? getError().getMessage() : SwingUtil.RESOURCE.getString("Error");
+    messageLabel.setText(mess);
+  }
+
+  /**
+   * Liefert den angezeigten Fehler.
+   */
+  public Throwable getError() {
+    return err;
+  }
+
+  /**
+   * Setzt den angezeigten Fehler.
+   */
+  public void setError(Throwable err) {
+    this.err = err;
+    if ( err == null )
+      detailsTextArea.setText("");
+    else
+      err.printStackTrace(detailsPrintStream);
+    detailsTextArea.select(0,0);
+  }
+
+  /**
+   * Zeigt einen Fehler-Dialog an.
+   * @param parent      uebergeordnetes Fenster (kann <code>null</code> sein!)
+   * @param err         darzustellender Fehler
+   * @param title       Titel fuer das Fenster (kann <code>null</code> sein!)
+   * @param errMessage  Meldung, die zu dem Fehler angezeigt angezeigt wird
+   *                    (kann <code>null</code> sein!)
+   */
+  public static void show(Component parent, Throwable err, String title, String errMessage) {
+    new ExceptionDialog(parent,err,title,errMessage).setVisible(true);
+  }
+
+  /**
+   * Zeigt einen Fehler-Dialog an.
+   * @param parent   uebergeordnetes Fenster (kann <code>null</code> sein!)
+   * @param err      darzustellender Fehler
+   */
+  public static void show(Component parent, Throwable err) {
+    new ExceptionDialog(parent,err).setVisible(true);
+  }
+
+  /**
+   * Zeigt einen Fehler-Dialog an.
+   * @param err darzustellender Fehler
+   */
+  public static void show(Throwable err) {
+    new ExceptionDialog(null,err).setVisible(true);
+  }
+
+  /**
+   * Zeigt einen Fehler-Dialog an.
+   * @param parent      uebergeordnetes Fenster (kann <code>null</code> sein!)
+   * @param err         darzustellender Fehler
+   * @param title       Titel fuer das Fenster (kann <code>null</code> sein!)
+   * @param errMessage  Meldung, die zu dem Fehler angezeigt angezeigt wird
+   *                    (kann <code>null</code> sein!)
+   * @param showDetails wenn {@code true} werden die Details initial angezeigt
+   */
+  public static void show(Component parent, Throwable err, String title, String errMessage, boolean showDetails) {
+    new ExceptionDialog(parent,err,title,errMessage,showDetails).setVisible(true);
+  }
+
+  /**
+   * Zeigt einen Fehler-Dialog an.
+   * @param parent   uebergeordnetes Fenster (kann <code>null</code> sein!)
+   * @param err      darzustellender Fehler
+   * @param showDetails wenn {@code true} werden die Details initial angezeigt
+   */
+  public static void show(Component parent, Throwable err, boolean showDetails) {
+    show(parent,err,null,null,showDetails);
+  }
+
+  /**
+   * Zeigt einen Fehler-Dialog an.
+   * @param err darzustellender Fehler
+   * @param showDetails wenn {@code true} werden die Details initial angezeigt
+   */
+  public static void show(Throwable err, boolean showDetails) {
+    show(null,err,showDetails);
+  }
+}

Modified: trunk/src/schmitzm/swing/ExpansionBar.java
===================================================================
--- trunk/src/schmitzm/swing/ExpansionBar.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/ExpansionBar.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,16 +1,34 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing;
-
 import java.awt.Color;
 import java.awt.Container;
 import java.awt.Dimension;
@@ -26,558 +44,558 @@
 import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JProgressBar;
-
-/**
- * Ein ExpansionBar aehnelt einem {@link JProgressBar}, mit dem Unterschied,
- * dass die Auspraegung des ExpansionBar nicht nur in eine Richtung gehen
- * kann (unten nach oben, oder links nach rechts), sondern ausgehend von einem
- * vorgegebenen Mitte-Wert in beide Richtungen, je nachdem, ob der gesetzte
- * Wert groesser oder kleiner ist als der Mitte-Wert.<br>
- * Waehrend der {@link JProgressBar} als Status-Balken aufgefasst werden kann,
- * der stetig fortschreitet, dient der der ExpansionBar auch der Anzeige von
- * negativen Werten (z.B. Abweichungswerten oder Amplituden). Fuer die
- * Abweichung koennen je ein oberer und unterer Grenzwert festgelegt werden.
- * Liegt der aktuelle Wert des Balken innerhalb dieser Toleranz, wird er
- * gruen angezeigt, ansonsten rot.<br>
- * Optional koennen fuer den Balken Labels mit den Grenz-Werten (Minimum,
- * Mitte, Maximum) angezeigt werden (siehe {@link #setValueLabelsPainted(boolean)}.
- * Dies ist per Default jedoch deaktiviert.<br>
- * <b>Bemerke:</b><br>
- * Bei vertikaler Darstellung gibt es noch Probleme mit der Label-Darstellung!
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- * @todo Probleme mit vertikaler Label-Darstellung beheben
- */
-public class ExpansionBar extends Container {
-  /** Konstante fuer eine lineare Darstellung des Balken. */
-  public static final int LINEAR = 9;
-  /** Konstante fuer eine logarithmische Darstellung des Balken. */
-  public static final int LOGARITHMIC = 8;
-  /** Konstante fuer eine vertikale Ausrichtung des Balken.
-   *  @see JProgressBar#VERTICAL */
-  public static final int VERTICAL = JProgressBar.VERTICAL;
-  /** Konstante fuer eine horizontale Ausrichtung des Balken.
-   *  @see JProgressBar#HORIZONTAL */
-  public static final int HORIZONTAL = JProgressBar.HORIZONTAL;
-
-  /** Speichert den Umrechnungsfaktor, um von den gesetzten double-Werten
-   *  auf Integer fuer die {@link JProgressBar}-Instanzen umzurechnen.
-   *  @see #convertToProgressBarValue(double)
-   */
-  protected int fracFact = 0;
-
-  /** Speichert die Farbe, in der der Balken angezeigt wird, wenn der
-   *  Wert innerhalb der Toleranz liegt. <br>
-   *  Default: {@linkplain Color#RED Gruen}*/
-  protected Color toleranceColor = Color.GREEN;
-
-  /** Speichert die Farbe, in der der Balken angezeigt wird, wenn der
-   *  Wert ausserhalb der Toleranz liegt.<br>
-   *  Default: {@linkplain Color#RED Rot} */
-  protected Color intoleranceColor = Color.RED;
-
-  // Beispiel-Schriftart fuer die Labels
-  private Font sampleFont = new JLabel().getFont();
-
-  // Label fuer Wert-Anzeige
-  private JLabel       minLabel = new JLabel();
-  private JLabel       midLabel = new JLabel();
-  private JLabel       maxLabel = new JLabel();
-  // Progressbars fuer die positive und negative Richtung
-  private JProgressBar negBar;
-  private JProgressBar posBar;
-  private JPanel       barContainer = new JPanel();
-
-  // Konfigurationsparameter
-  private double       min           = -100;
-  private int          barMin        = -100;
-  private double       max           = 100;
-  private int          barMax        = 100;
-  private double       mid           = 0;
-  private int          barMid        = 0;
-  private double       minTol        = 0;
-  private double       maxTol        = 0;
-  private int          orient        = HORIZONTAL;
-  private int          type          = LINEAR;
-  private double       value         = 0;
-  private boolean      stringPainted = true;
-  private NumberFormat barNumFormat  = new DecimalFormat("0.00%");
-  private NumberFormat infoNumFormat = new DecimalFormat("0.00%");
-
-  /**
-   * Erzeugt einen neuen linearen Balken. Als Mitte-Wert wird 0 gesetzt und die
-   * Toleranz ist nach oben und unten gleich.<br>
-   * Die Minimum-, Mitte- und Maximum-Label werden
-   * standardmaessig nicht angezeigt, wohl aber der aktuelle Balkenwert.
-   * @param orient    Orientierung des Balken (<code>ExpansionBar.HORIZONTAL</code>
-   *                  oder <code>ExpansionBar.VERTICAL</code>
-   * @param min       Minimalwert des Balkens
-   * @param max       Maximalwert des Balkens
-   * @param tol       Toleranzwert nach oben/unten bis zu dem der Balken gruen
-   *                  dargestellt wird (muss zwischen <code>0</code> und
-   *                  <code>max</code> liegen)
-   * @param form      Bestimmt die Darstellung der Werte im Anzeige-Label des
-   *                  Balken und in der etwaigen Info-Leiste
-   * @see #setValueLabelsPainted(boolean)
-   * @see #setStringPainted(boolean)
-   * @exception IllegalArgumentException falls die Konstellation der angegeben
-   *            Werte unzulaessig ist
-   */
-  public ExpansionBar(int orient, double min, double max, double tol, NumberFormat form) {
-    this(orient,LINEAR,min,max,tol,form);
-  }
-
-  /**
-   * Erzeugt einen neuen Balken. Als Mitte-Wert wird 0 gesetzt und die
-   * Toleranz ist nach oben und unten gleich.<br>
-   * Die Minimum-, Mitte- und Maximum-Label werden
-   * standardmaessig nicht angezeigt, wohl aber der aktuelle Balkenwert.
-   * @param orient    Orientierung des Balken (<code>ExpansionBar.HORIZONTAL</code>
-   *                  oder <code>ExpansionBar.VERTICAL</code>
-   * @param type      Darstellung des Balken (<code>ExpansionBar.LINEAR</code>
-   *                  oder <code>ExpansionBar.LOGARITHMIC</code>
-   * @param min       Minimalwert des Balkens
-   * @param max       Maximalwert des Balkens
-   * @param tol       Toleranzwert nach oben/unten bis zu dem der Balken gruen
-   *                  dargestellt wird (muss zwischen <code>0</code> und
-   *                  <code>max</code> liegen)
-   * @param form      Bestimmt die Darstellung der Werte im Anzeige-Label des
-   *                  Balken und in der etwaigen Info-Leiste
-   * @see #setValueLabelsPainted(boolean)
-   * @see #setStringPainted(boolean)
-   * @exception IllegalArgumentException falls die Konstellation der angegeben
-   *            Werte unzulaessig ist
-   */
-  public ExpansionBar(int orient, int type, double min, double max, double tol, NumberFormat form) {
-    this(orient,type,min,max,0.0,-tol,tol,0.0,form,form);
-  }
-
-  /**
-   * Erzeugt einen neuen linearen Balken. Die Toleranz vom Mitte-Wert ist nach oben
-   * und unten gleich.<br>
-   * Die Minimum-, Mitte- und Maximum-Label werden
-   * standardmaessig nicht angezeigt, wohl aber der aktuelle Balkenwert.
-   * @param orient    Orientierung des Balken (<code>ExpansionBar.HORIZONTAL</code>
-   *                  oder <code>ExpansionBar.VERTICAL</code>
-   * @param min       Minimalwert des Balkens
-   * @param max       Maximalwert des Balkens
-   * @param mid       Mitte-Wert des Balkens (muss zwischen <code>min</code> und
-   *                  <code>max</code> liegen)
-   * @param tol       Toleranzwert (relativ zur Mitte!) bis zu dem der Balken gruen
-   *                  dargestellt wird (muss zwischen <code>0</code> und
-   *                  <code>max</code> liegen)
-   * @param form      Bestimmt die Darstellung der Werte im Anzeige-Label des
-   *                  Balken und in der etwaigen Info-Leiste
-   * @see #setValueLabelsPainted(boolean)
-   * @see #setStringPainted(boolean)
-   * @exception IllegalArgumentException falls die Konstellation der angegeben
-   *            Werte unzulaessig ist
-   */
-  public ExpansionBar(int orient, double min, double max, double mid, double tol, NumberFormat form) {
-    this(orient,LINEAR,min,max,mid,tol,form);
-  }
-
-  /**
-   * Erzeugt einen neuen Balken. Die Toleranz vom Mitte-Wert ist nach oben
-   * und unten gleich.<br>
-   * Die Minimum-, Mitte- und Maximum-Label werden
-   * standardmaessig nicht angezeigt, wohl aber der aktuelle Balkenwert.
-   * @param orient    Orientierung des Balken (<code>ExpansionBar.HORIZONTAL</code>
-   *                  oder <code>ExpansionBar.VERTICAL</code>
-   * @param type      Darstellung des Balken (<code>ExpansionBar.LINEAR</code>
-   *                  oder <code>ExpansionBar.LOGARITHMIC</code>
-   * @param min       Minimalwert des Balkens
-   * @param max       Maximalwert des Balkens
-   * @param mid       Mitte-Wert des Balkens (muss zwischen <code>min</code> und
-   *                  <code>max</code> liegen)
-   * @param tol       Toleranzwert (relativ zur Mitte!) bis zu dem der Balken gruen
-   *                  dargestellt wird (muss zwischen <code>0</code> und
-   *                  <code>max</code> liegen)
-   * @param form      Bestimmt die Darstellung der Werte im Anzeige-Label des
-   *                  Balken und in der etwaigen Info-Leiste
-   * @see #setValueLabelsPainted(boolean)
-   * @see #setStringPainted(boolean)
-   * @exception IllegalArgumentException falls die Konstellation der angegeben
-   *            Werte unzulaessig ist
-   */
-  public ExpansionBar(int orient, int type, double min, double max, double mid, double tol, NumberFormat form) {
-    this(orient,type,min,max,mid,mid-tol,mid+tol,mid,form,form);
-  }
-
-  /**
-   * Erzeugt einen neuen Balken. Die Minimum-, Mitte- und Maximum-Label werden
-   * standardmaessig nicht angezeigt, wohl aber der aktuelle Balkenwert.
-   * @param orient    Orientierung des Balken (<code>ExpansionBar.HORIZONTAL</code>
-   *                  oder <code>ExpansionBar.VERTICAL</code>
-   * @param type      Darstellung des Balken (<code>ExpansionBar.LINEAR</code>
-   *                  oder <code>ExpansionBar.LOGARITHMIC</code>
-   * @param min       Minimalwert des Balkens
-   * @param max       Maximalwert des Balkens
-   * @param mid       Mitte-Wert des Balkens (muss zwischen <code>min</code> und
-   *                  <code>max</code> liegen)
-   * @param minTol    <b>Absoluter</b> Toleranzwert nach unten bis zu dem der Balken gruen
-   *                  dargestellt wird (muss zwischen <code>min</code> und
-   *                  <code>mid</code> liegen)
-   * @param maxTol    <b>Absoluter</b> Toleranzwert nach oben bis zu dem der Balken gruen
-   *                  dargestellt wird (muss zwischen <code>mid</code> und
-   *                  <code>max</code> liegen)
-   * @param initValue Initialer Wert den der Balken annimmt
-   * @param barForm   Bestimmt die Darstellung der Werte im Anzeige-Label des
-   *                  Balken
-   * @param infoForm  Bestimmt die Darstellung der Werte im etwaigen Info-Label
-   *                  unterhalb des Balken
-   * @see #setValueLabelsPainted(boolean)
-   * @see #setStringPainted(boolean)
-   * @exception IllegalArgumentException falls die Konstellation der angegeben
-   *            Werte unzulaessig ist
-   */
-  public ExpansionBar(int orient, int type, double min, double max, double mid, double minTol, double maxTol, double initValue, NumberFormat barForm, NumberFormat infoForm) {
-    super();
-    this.min       = min;
-    this.max       = max;
-    this.mid       = mid;
-    this.minTol    = minTol;
-    this.maxTol    = maxTol;
-    this.orient    = orient;
-    this.type      = type;
-    if ( barForm != null )
-      this.barNumFormat = barForm;
-    if ( infoForm != null )
-      this.infoNumFormat = infoForm;
-    checkValues();
-
-    // Der Progress-Bar kann nur Integers darstellen.
-    // Damit auch kleinere Bereiche (z.B. zwischen 0 und 1) fliessend
-    // dargestellt werden koennen, wird der Bereich auf (mind. 1000 Werte)
-    // skaliert
-    this.fracFact = 1;
-    while(  (max-mid)*fracFact < 1000 || (mid-min)*fracFact < 1000 )
-      fracFact *= 10;
-    this.barMin   = convertToProgressBarValue(min);
-    this.barMax   = convertToProgressBarValue(max);
-    this.barMid   = convertToProgressBarValue(mid);
-
-    // Label erzeugen
-    if (orient == VERTICAL)
-      // Label bekommen vertikale Schrift
-      sampleFont = sampleFont.deriveFont(AffineTransform.getRotateInstance(Math.PI / 2));
-    this.minLabel = new JLabel(infoNumFormat.format(min));
-    this.midLabel = new JLabel(infoNumFormat.format(mid));
-    this.maxLabel = new JLabel(infoNumFormat.format(max));
-    minLabel.setFont(sampleFont);
-    midLabel.setFont(sampleFont);
-    maxLabel.setFont(sampleFont);
-    setValueLabelsPainted(false); // Wert-Labels werden per Default NICHT angezeigt
-
-    // Das Ausgeben des Wert-Strings bewirkt, dass die Balken nicht in
-    // kleinen Bloecken dargestellt werden, sondern durchgehend (letztes
-    // ist notwendig, damit das "Tricksen" mit den Vorder/Hintergrundfarben
-    // beim Negatv-Balken den gewuenschten visuellen Effekt hat!)
-    // --> Es soll aber trotzdem keine (oder hoechstens beim Positiv-Balken)
-    //     Strings angezeigt werden
-    // --> getString()-Methode ueberschreiben und NICHTS zurueckgeben
-    this.posBar = new JProgressBar(orient,barMid,barMax) {
-      public String getString() { return stringPainted ? barNumFormat.format(value) : ""; }
-    };
-    this.negBar = new JProgressBar(orient,barMin,barMid) {
-      public String getString() { return ""; } };
-     // WICHTIG wegen Farbeffekt!!
-    posBar.setStringPainted(true);
-    negBar.setStringPainted(true);
-    posBar.setMinimumSize( new Dimension(0,0) );
-    negBar.setMinimumSize( new Dimension(0,0) );
-    // Negativ-Balken wird invertiert dargestellt, so dass es den Anschein
-    // bekommt, er wuerde sich von rechts nach links (oben nach unten)
-    // bewegen!!!
-    negBar.setForeground( posBar.getBackground() );
-
-    // ProgressBars erhalten keine eigene Border, sondern werden in einen
-    // Container eingefuegt, der eine Border erhaelt (WCIHTIG, da sonst die
-    // Border des Nagativ-Balken in der "Vordergrundfarbe" angezeigt wird und
-    // immer sichtbar ist)
-    posBar.setBorder( BorderFactory.createEmptyBorder() );
-    negBar.setBorder( BorderFactory.createEmptyBorder() );
-    barContainer.setBorder( BorderFactory.createLoweredBevelBorder() );
-    barContainer.setLayout( new GridBagLayout() );
-    // Zwischen die beiden Progress-Bars kommt ein Trennstrich
-    JLabel divComp = new JLabel();
-    divComp.setBorder( BorderFactory.createLineBorder(Color.DARK_GRAY));
-
-    // Komponenten in Container einfuegen
-    this.setLayout( new GridBagLayout() );
-    if ( orient == HORIZONTAL ) {
-      barContainer.add(negBar,new GridBagConstraints(0,0,1,1,0.5,1.0,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
-      barContainer.add(divComp,new GridBagConstraints(1,0,1,1,0.0,1.0,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
-      barContainer.add(posBar,new GridBagConstraints(2,0,1,1,0.5,1.0,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
-      add(barContainer, new GridBagConstraints(0,0,1,1,1.0,1.0,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
-      add(minLabel,new GridBagConstraints(0,1,1,1,1.0,1.0,GridBagConstraints.NORTHWEST,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
-      add(midLabel,new GridBagConstraints(0,1,1,1,1.0,1.0,GridBagConstraints.NORTH,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
-      add(maxLabel,new GridBagConstraints(0,1,1,1,1.0,1.0,GridBagConstraints.NORTHEAST,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
-    } else {
-      barContainer.add(posBar,new GridBagConstraints(0,0,1,1,1.0,0.5,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
-      barContainer.add(divComp,new GridBagConstraints(0,1,1,1,1.0,0.0,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
-      barContainer.add(negBar,new GridBagConstraints(0,2,1,1,1.0,0.5,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
-      add(barContainer, new GridBagConstraints(0,0,1,1,1.0,1.0,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
-      add(minLabel,new GridBagConstraints(1,0,1,1,1.0,1.0,GridBagConstraints.NORTH,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
-      add(midLabel,new GridBagConstraints(1,0,1,1,1.0,1.0,GridBagConstraints.CENTER,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
-      add(maxLabel,new GridBagConstraints(1,0,1,1,1.0,1.0,GridBagConstraints.SOUTH,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
-    }
-    // Default-Wert setzen
-    setValue(initValue);
-  }
-
-  /**
-   * Der ExpansionBar ist ueber zwei {@link JProgressBar}s realisiert. Diese
-   * koennen nur Integers darstellen. Damit auch kleinere Bereiche (z.B.
-   * zwischen 0 und 1) fliessend dargestellt werden koennen, wird der Bereich
-   * auf (mind. 1000 Werte) skaliert. Desweiteren wird ggf. auf eine
-   * logarithmische Darstellung umgerechnet.
-   * @param val umzurechnender Wert
-   * @see #fracFact
-   */
-  protected int convertToProgressBarValue(double val) {
-    if ( type == LOGARITHMIC ) {
-      if ( val >=0 )
-        val = Math.log(1 + val);
-      else
-        val = -Math.log(1 + -val);
-    }
-    return (int)Math.round(val*fracFact);
-  }
-
-  /**
-   * Prueft die durch den Konstruktor gesetzten Initialisierungswerte auf
-   * korrektheit.
-   * <ol>
-   * <li><code>min <= max</code></li>
-   * <li><code>min <= mid <= max</code></li>
-   * <li><code>min <= minTol <= mid</code></li>
-   * <li><code>mid <= maxTol <= max</code></li>
-   * <li><code>orient == ExpansionBar.HORIZONTAL || orient == ExpansionBar.VERTICAL</code></li>
-   * </ol>
-   */
-  protected void checkValues() {
-    if ( min > max )
-      throw new IllegalArgumentException("Minimum value must be less than maximum!");
-    if ( mid < min || mid > max )
-      throw new IllegalArgumentException("Middle value must be between minimum and maximum!");
-    if ( minTol < min || minTol > mid )
-      throw new IllegalArgumentException("Minimum tolerance must be between minimum and middle!");
-    if ( maxTol < mid || maxTol > max )
-      throw new IllegalArgumentException("Maximum tolerance must be between middle and maximum!");
-    if ( orient != HORIZONTAL && orient != VERTICAL )
-      throw new IllegalArgumentException("Orientation value must be ExpansionBar.HORIZONTAL or ExpansionBar.VERTICAL!");
-  }
-
-  /**
-   * Liefert den Minimum-Wert des Balkens.
-   */
-  public double getMinimum() {
-    return min;
-  }
-
-  /**
-   * Liefert den Maximum-Wert des Balkens.
-   */
-  public double getMaximum() {
-    return max;
-  }
-
-  /**
-   * Liefert den Mitte-Wert des Balkens.
-   */
-  public double getMiddle() {
-    return mid;
-  }
-
-  /**
-   * Liefert den (absoluten) Wert nach unten, bis zu dessen Wert der
-   * Balkens in gruen dargstellt wird.
-   */
-  public double getMinimumTolerance() {
-    return minTol;
-  }
-
-  /**
-   * Setzt den (absoluten) Wert nach unten, bis zu dessen Wert der
-   * Balkens in gruen dargstellt wird.
-   */
-  public void setMinimumTolerance(double minTol) {
-    if ( minTol < min || minTol > mid )
-      throw new IllegalArgumentException("Minimum tolerance must be between minimum and middle!");
-    this.minTol = minTol;;
-    updateForeground();
-  }
-
-  /**
-   * Liefert den (absoluten) Wert nach oben, bis zu dessen Wert der
-   * Balkens in gruen dargstellt wird.
-   */
-  public double getMaximumTolerance() {
-    return maxTol;
-  }
-
-  /**
-   * Setzt den (absoluten) Wert nach oben, bis zu dessen Wert der
-   * Balkens in gruen dargstellt wird.
-   */
-  public void setMaximumTolerance(double maxTol) {
-    if ( maxTol < mid || maxTol > max )
-      throw new IllegalArgumentException("Maximum tolerance must be between middle and maximum!");
-    this.maxTol = maxTol;
-    updateForeground();
-  }
-
-  /**
-   * Liefert den aktuellen Wert des Balkens.
-   */
-  public double getValue() {
-    return value;
-  }
-
-  /**
-   * Setzt den aktuellen Wert des Balkens.
-   */
-  public void setValue(double value) {
-    this.value = value;
-    // Farbe aktualsieren
-    updateForeground();
-
-    // angezeigt wird nur bis zum Minimum/Maximum
-    value = Math.min(value,max);
-    value = Math.max(value,min);
-
-    if (value > mid) {
-      // Bei werden oberhalb der Mitte wird der Negativ-Balken auf
-      // die Mitte (also "nichts") gesetzt und der Positiv-Balken
-      // auf den Wert oberhalb der Mitte
-      negBar.setValue(barMid);
-      posBar.setValue(convertToProgressBarValue(value)-barMid);
-    } else {
-      // Bei werden unterhalb der Mitte wird der Positiv-Balken auf
-      // die Mitte (also "nichts") gesetzt und der Negativ-Balken
-      // auf den Wert oberhalb der Mitte
-      posBar.setValue(barMid);
-      negBar.setValue(convertToProgressBarValue(value));
-    }
-    // String neu setzten, damit er neu angezeigt wird. Diese Aktualisierung
-    // erfolgt sonst nicht immer korrekt?!
-    posBar.setString( posBar.getString() );
-  }
-
-  /**
-   * Prueft, ob die Minimum/Mitte/Maximum-Labels angezeigt werden.
-   */
-  public boolean getValueLabelsPainted() {
-    return minLabel.isVisible();
-  }
-
-  /**
-   * Zeigt die Minimum/Mitte/Maximum-Labels an oder verbirgt sie.
-   */
-  public void setValueLabelsPainted(boolean visible) {
-    minLabel.setVisible(visible);
-    midLabel.setVisible(visible);
-    maxLabel.setVisible(visible);
-  }
-
-  /**
-   * Prueft, ob der Balken-Wert angezeigt wird.
-   */
-  public boolean getStringPainted() {
-    return this.stringPainted;
-  }
-
-  /**
-   * Zeigt den Balken-Wert an oder verbirgt ihn.
-   */
-  public void setStringPainted(boolean strPaint) {
-    this.stringPainted = strPaint;
-    // irgendwas "anzeigen" damit die Darstellung des
-    // Progressbars aktualisiert wird
-    posBar.setString("");
-  }
-
-  /**
-   * Aktualisiert die Vordergrundfarbe des Balkens, je nachdem, ob der
-   * Balkenwert aktuell innerhalb oder ausserhalb der Toleranz liegt.
-   */
-  protected void updateForeground() {
-    if ( minTol <= value && value <= maxTol )
-      setForeground( toleranceColor );
-    else
-      setForeground( intoleranceColor );
-  }
-
-  /**
-   * Setzt die Farbe, die angezeigt wird, wenn der Balkenwert innerhalb der
-   * Toleranz liegt.
-   */
-  public void setToleranceColor(Color color) {
-    this.toleranceColor = color;
-    updateForeground();
-  }
-
-  /**
-   * Liefert die Farbe, die angezeigt wird, wenn der Balkenwert innerhalb der
-   * Toleranz liegt.
-   */
-  public Color getToleranceColor() {
-    return toleranceColor;
-  }
-
-  /**
-   * Setzt die Farbe, die angezeigt wird, wenn der Balkenwert ausserhalb der
-   * Toleranz liegt.
-   */
-  public void setIntoleranceColor(Color color) {
-    this.intoleranceColor = color;
-    updateForeground();
-  }
-
-  /**
-   * Liefert die Farbe, die angezeigt wird, wenn der Balkenwert ausserhalb der
-   * Toleranz liegt.
-   */
-  public Color getIntoleranceColor() {
-    return intoleranceColor;
-  }
-
-  /**
-   * Liefert die aktuelle Vordergrund-Farbe des Balkens.
-   */
-  public Color getForeground() {
-    return posBar.getForeground();
-  }
-
-  /**
-   * Setzt die Vordergrundfarbe des Balken unabhaengig davon, ob der
-   * Wert innerhalb oder ausserhalb der Toleranz liegt.<br>
-   * <b>Bemerke:</b><br>
-   * Dies beeinflusst die (In)Toleranz-Farben nicht! Bei der naechsten
-   * Aktualisierung (z.B. {@link #setValue(double)}) wird die Farbe wieder
-   * entsprechend der (In)Toleranz-Einstellungen gesetzt.
-   * @see #setToleranceColor(Color)
-   * @see #setIntoleranceColor(Color)
-   */
-  public void setForeground(Color color) {
-    posBar.setForeground( color );
-    negBar.setBackground( color );
-  }
-
-  /**
-   * Liefert die Hintergrund-Farbe des Balkens.
-   */
-  public Color getBackground() {
-    return posBar.getBackground();
-  }
-
-  /**
-   * Setzt die Hintergrund-Farbe des Balkens.
-   */
-  public void setBackground(Color color) {
-    posBar.setBackground( color );
-    negBar.setForeground( color );
-  }
-
-}
+
+/**
+ * Ein ExpansionBar aehnelt einem {@link JProgressBar}, mit dem Unterschied,
+ * dass die Auspraegung des ExpansionBar nicht nur in eine Richtung gehen
+ * kann (unten nach oben, oder links nach rechts), sondern ausgehend von einem
+ * vorgegebenen Mitte-Wert in beide Richtungen, je nachdem, ob der gesetzte
+ * Wert groesser oder kleiner ist als der Mitte-Wert.<br>
+ * Waehrend der {@link JProgressBar} als Status-Balken aufgefasst werden kann,
+ * der stetig fortschreitet, dient der der ExpansionBar auch der Anzeige von
+ * negativen Werten (z.B. Abweichungswerten oder Amplituden). Fuer die
+ * Abweichung koennen je ein oberer und unterer Grenzwert festgelegt werden.
+ * Liegt der aktuelle Wert des Balken innerhalb dieser Toleranz, wird er
+ * gruen angezeigt, ansonsten rot.<br>
+ * Optional koennen fuer den Balken Labels mit den Grenz-Werten (Minimum,
+ * Mitte, Maximum) angezeigt werden (siehe {@link #setValueLabelsPainted(boolean)}.
+ * Dies ist per Default jedoch deaktiviert.<br>
+ * <b>Bemerke:</b><br>
+ * Bei vertikaler Darstellung gibt es noch Probleme mit der Label-Darstellung!
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ * @todo Probleme mit vertikaler Label-Darstellung beheben
+ */
+public class ExpansionBar extends Container {
+  /** Konstante fuer eine lineare Darstellung des Balken. */
+  public static final int LINEAR = 9;
+  /** Konstante fuer eine logarithmische Darstellung des Balken. */
+  public static final int LOGARITHMIC = 8;
+  /** Konstante fuer eine vertikale Ausrichtung des Balken.
+   *  @see JProgressBar#VERTICAL */
+  public static final int VERTICAL = JProgressBar.VERTICAL;
+  /** Konstante fuer eine horizontale Ausrichtung des Balken.
+   *  @see JProgressBar#HORIZONTAL */
+  public static final int HORIZONTAL = JProgressBar.HORIZONTAL;
+
+  /** Speichert den Umrechnungsfaktor, um von den gesetzten double-Werten
+   *  auf Integer fuer die {@link JProgressBar}-Instanzen umzurechnen.
+   *  @see #convertToProgressBarValue(double)
+   */
+  protected int fracFact = 0;
+
+  /** Speichert die Farbe, in der der Balken angezeigt wird, wenn der
+   *  Wert innerhalb der Toleranz liegt. <br>
+   *  Default: {@linkplain Color#RED Gruen}*/
+  protected Color toleranceColor = Color.GREEN;
+
+  /** Speichert die Farbe, in der der Balken angezeigt wird, wenn der
+   *  Wert ausserhalb der Toleranz liegt.<br>
+   *  Default: {@linkplain Color#RED Rot} */
+  protected Color intoleranceColor = Color.RED;
+
+  // Beispiel-Schriftart fuer die Labels
+  private Font sampleFont = new JLabel().getFont();
+
+  // Label fuer Wert-Anzeige
+  private JLabel       minLabel = new JLabel();
+  private JLabel       midLabel = new JLabel();
+  private JLabel       maxLabel = new JLabel();
+  // Progressbars fuer die positive und negative Richtung
+  private JProgressBar negBar;
+  private JProgressBar posBar;
+  private JPanel       barContainer = new JPanel();
+
+  // Konfigurationsparameter
+  private double       min           = -100;
+  private int          barMin        = -100;
+  private double       max           = 100;
+  private int          barMax        = 100;
+  private double       mid           = 0;
+  private int          barMid        = 0;
+  private double       minTol        = 0;
+  private double       maxTol        = 0;
+  private int          orient        = HORIZONTAL;
+  private int          type          = LINEAR;
+  private double       value         = 0;
+  private boolean      stringPainted = true;
+  private NumberFormat barNumFormat  = new DecimalFormat("0.00%");
+  private NumberFormat infoNumFormat = new DecimalFormat("0.00%");
+
+  /**
+   * Erzeugt einen neuen linearen Balken. Als Mitte-Wert wird 0 gesetzt und die
+   * Toleranz ist nach oben und unten gleich.<br>
+   * Die Minimum-, Mitte- und Maximum-Label werden
+   * standardmaessig nicht angezeigt, wohl aber der aktuelle Balkenwert.
+   * @param orient    Orientierung des Balken (<code>ExpansionBar.HORIZONTAL</code>
+   *                  oder <code>ExpansionBar.VERTICAL</code>
+   * @param min       Minimalwert des Balkens
+   * @param max       Maximalwert des Balkens
+   * @param tol       Toleranzwert nach oben/unten bis zu dem der Balken gruen
+   *                  dargestellt wird (muss zwischen <code>0</code> und
+   *                  <code>max</code> liegen)
+   * @param form      Bestimmt die Darstellung der Werte im Anzeige-Label des
+   *                  Balken und in der etwaigen Info-Leiste
+   * @see #setValueLabelsPainted(boolean)
+   * @see #setStringPainted(boolean)
+   * @exception IllegalArgumentException falls die Konstellation der angegeben
+   *            Werte unzulaessig ist
+   */
+  public ExpansionBar(int orient, double min, double max, double tol, NumberFormat form) {
+    this(orient,LINEAR,min,max,tol,form);
+  }
+
+  /**
+   * Erzeugt einen neuen Balken. Als Mitte-Wert wird 0 gesetzt und die
+   * Toleranz ist nach oben und unten gleich.<br>
+   * Die Minimum-, Mitte- und Maximum-Label werden
+   * standardmaessig nicht angezeigt, wohl aber der aktuelle Balkenwert.
+   * @param orient    Orientierung des Balken (<code>ExpansionBar.HORIZONTAL</code>
+   *                  oder <code>ExpansionBar.VERTICAL</code>
+   * @param type      Darstellung des Balken (<code>ExpansionBar.LINEAR</code>
+   *                  oder <code>ExpansionBar.LOGARITHMIC</code>
+   * @param min       Minimalwert des Balkens
+   * @param max       Maximalwert des Balkens
+   * @param tol       Toleranzwert nach oben/unten bis zu dem der Balken gruen
+   *                  dargestellt wird (muss zwischen <code>0</code> und
+   *                  <code>max</code> liegen)
+   * @param form      Bestimmt die Darstellung der Werte im Anzeige-Label des
+   *                  Balken und in der etwaigen Info-Leiste
+   * @see #setValueLabelsPainted(boolean)
+   * @see #setStringPainted(boolean)
+   * @exception IllegalArgumentException falls die Konstellation der angegeben
+   *            Werte unzulaessig ist
+   */
+  public ExpansionBar(int orient, int type, double min, double max, double tol, NumberFormat form) {
+    this(orient,type,min,max,0.0,-tol,tol,0.0,form,form);
+  }
+
+  /**
+   * Erzeugt einen neuen linearen Balken. Die Toleranz vom Mitte-Wert ist nach oben
+   * und unten gleich.<br>
+   * Die Minimum-, Mitte- und Maximum-Label werden
+   * standardmaessig nicht angezeigt, wohl aber der aktuelle Balkenwert.
+   * @param orient    Orientierung des Balken (<code>ExpansionBar.HORIZONTAL</code>
+   *                  oder <code>ExpansionBar.VERTICAL</code>
+   * @param min       Minimalwert des Balkens
+   * @param max       Maximalwert des Balkens
+   * @param mid       Mitte-Wert des Balkens (muss zwischen <code>min</code> und
+   *                  <code>max</code> liegen)
+   * @param tol       Toleranzwert (relativ zur Mitte!) bis zu dem der Balken gruen
+   *                  dargestellt wird (muss zwischen <code>0</code> und
+   *                  <code>max</code> liegen)
+   * @param form      Bestimmt die Darstellung der Werte im Anzeige-Label des
+   *                  Balken und in der etwaigen Info-Leiste
+   * @see #setValueLabelsPainted(boolean)
+   * @see #setStringPainted(boolean)
+   * @exception IllegalArgumentException falls die Konstellation der angegeben
+   *            Werte unzulaessig ist
+   */
+  public ExpansionBar(int orient, double min, double max, double mid, double tol, NumberFormat form) {
+    this(orient,LINEAR,min,max,mid,tol,form);
+  }
+
+  /**
+   * Erzeugt einen neuen Balken. Die Toleranz vom Mitte-Wert ist nach oben
+   * und unten gleich.<br>
+   * Die Minimum-, Mitte- und Maximum-Label werden
+   * standardmaessig nicht angezeigt, wohl aber der aktuelle Balkenwert.
+   * @param orient    Orientierung des Balken (<code>ExpansionBar.HORIZONTAL</code>
+   *                  oder <code>ExpansionBar.VERTICAL</code>
+   * @param type      Darstellung des Balken (<code>ExpansionBar.LINEAR</code>
+   *                  oder <code>ExpansionBar.LOGARITHMIC</code>
+   * @param min       Minimalwert des Balkens
+   * @param max       Maximalwert des Balkens
+   * @param mid       Mitte-Wert des Balkens (muss zwischen <code>min</code> und
+   *                  <code>max</code> liegen)
+   * @param tol       Toleranzwert (relativ zur Mitte!) bis zu dem der Balken gruen
+   *                  dargestellt wird (muss zwischen <code>0</code> und
+   *                  <code>max</code> liegen)
+   * @param form      Bestimmt die Darstellung der Werte im Anzeige-Label des
+   *                  Balken und in der etwaigen Info-Leiste
+   * @see #setValueLabelsPainted(boolean)
+   * @see #setStringPainted(boolean)
+   * @exception IllegalArgumentException falls die Konstellation der angegeben
+   *            Werte unzulaessig ist
+   */
+  public ExpansionBar(int orient, int type, double min, double max, double mid, double tol, NumberFormat form) {
+    this(orient,type,min,max,mid,mid-tol,mid+tol,mid,form,form);
+  }
+
+  /**
+   * Erzeugt einen neuen Balken. Die Minimum-, Mitte- und Maximum-Label werden
+   * standardmaessig nicht angezeigt, wohl aber der aktuelle Balkenwert.
+   * @param orient    Orientierung des Balken (<code>ExpansionBar.HORIZONTAL</code>
+   *                  oder <code>ExpansionBar.VERTICAL</code>
+   * @param type      Darstellung des Balken (<code>ExpansionBar.LINEAR</code>
+   *                  oder <code>ExpansionBar.LOGARITHMIC</code>
+   * @param min       Minimalwert des Balkens
+   * @param max       Maximalwert des Balkens
+   * @param mid       Mitte-Wert des Balkens (muss zwischen <code>min</code> und
+   *                  <code>max</code> liegen)
+   * @param minTol    <b>Absoluter</b> Toleranzwert nach unten bis zu dem der Balken gruen
+   *                  dargestellt wird (muss zwischen <code>min</code> und
+   *                  <code>mid</code> liegen)
+   * @param maxTol    <b>Absoluter</b> Toleranzwert nach oben bis zu dem der Balken gruen
+   *                  dargestellt wird (muss zwischen <code>mid</code> und
+   *                  <code>max</code> liegen)
+   * @param initValue Initialer Wert den der Balken annimmt
+   * @param barForm   Bestimmt die Darstellung der Werte im Anzeige-Label des
+   *                  Balken
+   * @param infoForm  Bestimmt die Darstellung der Werte im etwaigen Info-Label
+   *                  unterhalb des Balken
+   * @see #setValueLabelsPainted(boolean)
+   * @see #setStringPainted(boolean)
+   * @exception IllegalArgumentException falls die Konstellation der angegeben
+   *            Werte unzulaessig ist
+   */
+  public ExpansionBar(int orient, int type, double min, double max, double mid, double minTol, double maxTol, double initValue, NumberFormat barForm, NumberFormat infoForm) {
+    super();
+    this.min       = min;
+    this.max       = max;
+    this.mid       = mid;
+    this.minTol    = minTol;
+    this.maxTol    = maxTol;
+    this.orient    = orient;
+    this.type      = type;
+    if ( barForm != null )
+      this.barNumFormat = barForm;
+    if ( infoForm != null )
+      this.infoNumFormat = infoForm;
+    checkValues();
+
+    // Der Progress-Bar kann nur Integers darstellen.
+    // Damit auch kleinere Bereiche (z.B. zwischen 0 und 1) fliessend
+    // dargestellt werden koennen, wird der Bereich auf (mind. 1000 Werte)
+    // skaliert
+    this.fracFact = 1;
+    while(  (max-mid)*fracFact < 1000 || (mid-min)*fracFact < 1000 )
+      fracFact *= 10;
+    this.barMin   = convertToProgressBarValue(min);
+    this.barMax   = convertToProgressBarValue(max);
+    this.barMid   = convertToProgressBarValue(mid);
+
+    // Label erzeugen
+    if (orient == VERTICAL)
+      // Label bekommen vertikale Schrift
+      sampleFont = sampleFont.deriveFont(AffineTransform.getRotateInstance(Math.PI / 2));
+    this.minLabel = new JLabel(infoNumFormat.format(min));
+    this.midLabel = new JLabel(infoNumFormat.format(mid));
+    this.maxLabel = new JLabel(infoNumFormat.format(max));
+    minLabel.setFont(sampleFont);
+    midLabel.setFont(sampleFont);
+    maxLabel.setFont(sampleFont);
+    setValueLabelsPainted(false); // Wert-Labels werden per Default NICHT angezeigt
+
+    // Das Ausgeben des Wert-Strings bewirkt, dass die Balken nicht in
+    // kleinen Bloecken dargestellt werden, sondern durchgehend (letztes
+    // ist notwendig, damit das "Tricksen" mit den Vorder/Hintergrundfarben
+    // beim Negatv-Balken den gewuenschten visuellen Effekt hat!)
+    // --> Es soll aber trotzdem keine (oder hoechstens beim Positiv-Balken)
+    //     Strings angezeigt werden
+    // --> getString()-Methode ueberschreiben und NICHTS zurueckgeben
+    this.posBar = new JProgressBar(orient,barMid,barMax) {
+      public String getString() { return stringPainted ? barNumFormat.format(value) : ""; }
+    };
+    this.negBar = new JProgressBar(orient,barMin,barMid) {
+      public String getString() { return ""; } };
+     // WICHTIG wegen Farbeffekt!!
+    posBar.setStringPainted(true);
+    negBar.setStringPainted(true);
+    posBar.setMinimumSize( new Dimension(0,0) );
+    negBar.setMinimumSize( new Dimension(0,0) );
+    // Negativ-Balken wird invertiert dargestellt, so dass es den Anschein
+    // bekommt, er wuerde sich von rechts nach links (oben nach unten)
+    // bewegen!!!
+    negBar.setForeground( posBar.getBackground() );
+
+    // ProgressBars erhalten keine eigene Border, sondern werden in einen
+    // Container eingefuegt, der eine Border erhaelt (WCIHTIG, da sonst die
+    // Border des Nagativ-Balken in der "Vordergrundfarbe" angezeigt wird und
+    // immer sichtbar ist)
+    posBar.setBorder( BorderFactory.createEmptyBorder() );
+    negBar.setBorder( BorderFactory.createEmptyBorder() );
+    barContainer.setBorder( BorderFactory.createLoweredBevelBorder() );
+    barContainer.setLayout( new GridBagLayout() );
+    // Zwischen die beiden Progress-Bars kommt ein Trennstrich
+    JLabel divComp = new JLabel();
+    divComp.setBorder( BorderFactory.createLineBorder(Color.DARK_GRAY));
+
+    // Komponenten in Container einfuegen
+    this.setLayout( new GridBagLayout() );
+    if ( orient == HORIZONTAL ) {
+      barContainer.add(negBar,new GridBagConstraints(0,0,1,1,0.5,1.0,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
+      barContainer.add(divComp,new GridBagConstraints(1,0,1,1,0.0,1.0,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
+      barContainer.add(posBar,new GridBagConstraints(2,0,1,1,0.5,1.0,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
+      add(barContainer, new GridBagConstraints(0,0,1,1,1.0,1.0,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
+      add(minLabel,new GridBagConstraints(0,1,1,1,1.0,1.0,GridBagConstraints.NORTHWEST,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
+      add(midLabel,new GridBagConstraints(0,1,1,1,1.0,1.0,GridBagConstraints.NORTH,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
+      add(maxLabel,new GridBagConstraints(0,1,1,1,1.0,1.0,GridBagConstraints.NORTHEAST,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
+    } else {
+      barContainer.add(posBar,new GridBagConstraints(0,0,1,1,1.0,0.5,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
+      barContainer.add(divComp,new GridBagConstraints(0,1,1,1,1.0,0.0,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
+      barContainer.add(negBar,new GridBagConstraints(0,2,1,1,1.0,0.5,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
+      add(barContainer, new GridBagConstraints(0,0,1,1,1.0,1.0,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
+      add(minLabel,new GridBagConstraints(1,0,1,1,1.0,1.0,GridBagConstraints.NORTH,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
+      add(midLabel,new GridBagConstraints(1,0,1,1,1.0,1.0,GridBagConstraints.CENTER,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
+      add(maxLabel,new GridBagConstraints(1,0,1,1,1.0,1.0,GridBagConstraints.SOUTH,GridBagConstraints.NONE,new Insets(0,0,0,0),0,0));
+    }
+    // Default-Wert setzen
+    setValue(initValue);
+  }
+
+  /**
+   * Der ExpansionBar ist ueber zwei {@link JProgressBar}s realisiert. Diese
+   * koennen nur Integers darstellen. Damit auch kleinere Bereiche (z.B.
+   * zwischen 0 und 1) fliessend dargestellt werden koennen, wird der Bereich
+   * auf (mind. 1000 Werte) skaliert. Desweiteren wird ggf. auf eine
+   * logarithmische Darstellung umgerechnet.
+   * @param val umzurechnender Wert
+   * @see #fracFact
+   */
+  protected int convertToProgressBarValue(double val) {
+    if ( type == LOGARITHMIC ) {
+      if ( val >=0 )
+        val = Math.log(1 + val);
+      else
+        val = -Math.log(1 + -val);
+    }
+    return (int)Math.round(val*fracFact);
+  }
+
+  /**
+   * Prueft die durch den Konstruktor gesetzten Initialisierungswerte auf
+   * korrektheit.
+   * <ol>
+   * <li><code>min <= max</code></li>
+   * <li><code>min <= mid <= max</code></li>
+   * <li><code>min <= minTol <= mid</code></li>
+   * <li><code>mid <= maxTol <= max</code></li>
+   * <li><code>orient == ExpansionBar.HORIZONTAL || orient == ExpansionBar.VERTICAL</code></li>
+   * </ol>
+   */
+  protected void checkValues() {
+    if ( min > max )
+      throw new IllegalArgumentException("Minimum value must be less than maximum!");
+    if ( mid < min || mid > max )
+      throw new IllegalArgumentException("Middle value must be between minimum and maximum!");
+    if ( minTol < min || minTol > mid )
+      throw new IllegalArgumentException("Minimum tolerance must be between minimum and middle!");
+    if ( maxTol < mid || maxTol > max )
+      throw new IllegalArgumentException("Maximum tolerance must be between middle and maximum!");
+    if ( orient != HORIZONTAL && orient != VERTICAL )
+      throw new IllegalArgumentException("Orientation value must be ExpansionBar.HORIZONTAL or ExpansionBar.VERTICAL!");
+  }
+
+  /**
+   * Liefert den Minimum-Wert des Balkens.
+   */
+  public double getMinimum() {
+    return min;
+  }
+
+  /**
+   * Liefert den Maximum-Wert des Balkens.
+   */
+  public double getMaximum() {
+    return max;
+  }
+
+  /**
+   * Liefert den Mitte-Wert des Balkens.
+   */
+  public double getMiddle() {
+    return mid;
+  }
+
+  /**
+   * Liefert den (absoluten) Wert nach unten, bis zu dessen Wert der
+   * Balkens in gruen dargstellt wird.
+   */
+  public double getMinimumTolerance() {
+    return minTol;
+  }
+
+  /**
+   * Setzt den (absoluten) Wert nach unten, bis zu dessen Wert der
+   * Balkens in gruen dargstellt wird.
+   */
+  public void setMinimumTolerance(double minTol) {
+    if ( minTol < min || minTol > mid )
+      throw new IllegalArgumentException("Minimum tolerance must be between minimum and middle!");
+    this.minTol = minTol;;
+    updateForeground();
+  }
+
+  /**
+   * Liefert den (absoluten) Wert nach oben, bis zu dessen Wert der
+   * Balkens in gruen dargstellt wird.
+   */
+  public double getMaximumTolerance() {
+    return maxTol;
+  }
+
+  /**
+   * Setzt den (absoluten) Wert nach oben, bis zu dessen Wert der
+   * Balkens in gruen dargstellt wird.
+   */
+  public void setMaximumTolerance(double maxTol) {
+    if ( maxTol < mid || maxTol > max )
+      throw new IllegalArgumentException("Maximum tolerance must be between middle and maximum!");
+    this.maxTol = maxTol;
+    updateForeground();
+  }
+
+  /**
+   * Liefert den aktuellen Wert des Balkens.
+   */
+  public double getValue() {
+    return value;
+  }
+
+  /**
+   * Setzt den aktuellen Wert des Balkens.
+   */
+  public void setValue(double value) {
+    this.value = value;
+    // Farbe aktualsieren
+    updateForeground();
+
+    // angezeigt wird nur bis zum Minimum/Maximum
+    value = Math.min(value,max);
+    value = Math.max(value,min);
+
+    if (value > mid) {
+      // Bei werden oberhalb der Mitte wird der Negativ-Balken auf
+      // die Mitte (also "nichts") gesetzt und der Positiv-Balken
+      // auf den Wert oberhalb der Mitte
+      negBar.setValue(barMid);
+      posBar.setValue(convertToProgressBarValue(value)-barMid);
+    } else {
+      // Bei werden unterhalb der Mitte wird der Positiv-Balken auf
+      // die Mitte (also "nichts") gesetzt und der Negativ-Balken
+      // auf den Wert oberhalb der Mitte
+      posBar.setValue(barMid);
+      negBar.setValue(convertToProgressBarValue(value));
+    }
+    // String neu setzten, damit er neu angezeigt wird. Diese Aktualisierung
+    // erfolgt sonst nicht immer korrekt?!
+    posBar.setString( posBar.getString() );
+  }
+
+  /**
+   * Prueft, ob die Minimum/Mitte/Maximum-Labels angezeigt werden.
+   */
+  public boolean getValueLabelsPainted() {
+    return minLabel.isVisible();
+  }
+
+  /**
+   * Zeigt die Minimum/Mitte/Maximum-Labels an oder verbirgt sie.
+   */
+  public void setValueLabelsPainted(boolean visible) {
+    minLabel.setVisible(visible);
+    midLabel.setVisible(visible);
+    maxLabel.setVisible(visible);
+  }
+
+  /**
+   * Prueft, ob der Balken-Wert angezeigt wird.
+   */
+  public boolean getStringPainted() {
+    return this.stringPainted;
+  }
+
+  /**
+   * Zeigt den Balken-Wert an oder verbirgt ihn.
+   */
+  public void setStringPainted(boolean strPaint) {
+    this.stringPainted = strPaint;
+    // irgendwas "anzeigen" damit die Darstellung des
+    // Progressbars aktualisiert wird
+    posBar.setString("");
+  }
+
+  /**
+   * Aktualisiert die Vordergrundfarbe des Balkens, je nachdem, ob der
+   * Balkenwert aktuell innerhalb oder ausserhalb der Toleranz liegt.
+   */
+  protected void updateForeground() {
+    if ( minTol <= value && value <= maxTol )
+      setForeground( toleranceColor );
+    else
+      setForeground( intoleranceColor );
+  }
+
+  /**
+   * Setzt die Farbe, die angezeigt wird, wenn der Balkenwert innerhalb der
+   * Toleranz liegt.
+   */
+  public void setToleranceColor(Color color) {
+    this.toleranceColor = color;
+    updateForeground();
+  }
+
+  /**
+   * Liefert die Farbe, die angezeigt wird, wenn der Balkenwert innerhalb der
+   * Toleranz liegt.
+   */
+  public Color getToleranceColor() {
+    return toleranceColor;
+  }
+
+  /**
+   * Setzt die Farbe, die angezeigt wird, wenn der Balkenwert ausserhalb der
+   * Toleranz liegt.
+   */
+  public void setIntoleranceColor(Color color) {
+    this.intoleranceColor = color;
+    updateForeground();
+  }
+
+  /**
+   * Liefert die Farbe, die angezeigt wird, wenn der Balkenwert ausserhalb der
+   * Toleranz liegt.
+   */
+  public Color getIntoleranceColor() {
+    return intoleranceColor;
+  }
+
+  /**
+   * Liefert die aktuelle Vordergrund-Farbe des Balkens.
+   */
+  public Color getForeground() {
+    return posBar.getForeground();
+  }
+
+  /**
+   * Setzt die Vordergrundfarbe des Balken unabhaengig davon, ob der
+   * Wert innerhalb oder ausserhalb der Toleranz liegt.<br>
+   * <b>Bemerke:</b><br>
+   * Dies beeinflusst die (In)Toleranz-Farben nicht! Bei der naechsten
+   * Aktualisierung (z.B. {@link #setValue(double)}) wird die Farbe wieder
+   * entsprechend der (In)Toleranz-Einstellungen gesetzt.
+   * @see #setToleranceColor(Color)
+   * @see #setIntoleranceColor(Color)
+   */
+  public void setForeground(Color color) {
+    posBar.setForeground( color );
+    negBar.setBackground( color );
+  }
+
+  /**
+   * Liefert die Hintergrund-Farbe des Balkens.
+   */
+  public Color getBackground() {
+    return posBar.getBackground();
+  }
+
+  /**
+   * Setzt die Hintergrund-Farbe des Balkens.
+   */
+  public void setBackground(Color color) {
+    posBar.setBackground( color );
+    negBar.setForeground( color );
+  }
+
+}

Modified: trunk/src/schmitzm/swing/FileInputOption.java
===================================================================
--- trunk/src/schmitzm/swing/FileInputOption.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/FileInputOption.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,104 +1,122 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+import java.io.File;
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+import javax.swing.JFileChooser;
 
-package schmitzm.swing;
-
-import java.io.File;
+/**
+ * Diese Eingabe-Option dient dazu eine Datei-Angabe zu vorzunehmen. Dies
+ * kann ueber manuelle Eingabe erfolgen, oder durch Browsen mittels einem
+ * {@link JFileChooser}. Der Wert, den die Eingabe-Option repraesentiert stellt
+ * ein {@link File}-Objekt dar.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class FileInputOption extends BrowseInputOption {
+  private JFileChooser fileChooser = new JFileChooser();
 
-import javax.swing.JFileChooser;
-
-/**
- * Diese Eingabe-Option dient dazu eine Datei-Angabe zu vorzunehmen. Dies
- * kann ueber manuelle Eingabe erfolgen, oder durch Browsen mittels einem
- * {@link JFileChooser}. Der Wert, den die Eingabe-Option repraesentiert stellt
- * ein {@link File}-Objekt dar.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class FileInputOption extends BrowseInputOption {
-  private JFileChooser fileChooser = new JFileChooser();
-
-  /**
-   * Erzeugt eine neue Eingabe-Option.
-   * @param label Beschreibung der Eingabe-Option
-   * @param inputNeeded bestimmt, ob eine Eingabe erforderlich ist
-   * @param defValue Standard-Wert der vorgeblendet wird
-   */
-  public FileInputOption(String label, boolean inputNeeded, File defValue) {
-    super(label,inputNeeded,/*defValue == null ? new File(".") :*/ defValue);
-  }
-
-  /**
-   * Erzeugt eine neue Eingabe-Option.
-   * @param label Beschreibung der Eingabe-Option
-   * @param inputNeeded bestimmt, ob eine Eingabe erforderlich ist
-   */
-  public FileInputOption(String label, boolean inputNeeded) {
-    this(label,inputNeeded,null);
-  }
-
-  /**
-   * Liefert den Wert, der in der Option eingegeben wurde. Prueft zuerst
-   * auf Gueltigkeit und ruft dann {@link #performGetValue()} auf.
-   * @return <code>null</code> wenn die aktuelle Eingabe nicht zulaessig ist
-   *         (siehe {@link #isInputValid()})
-   */
-  public File getValue() {
-    return (File)super.getValue();
-  }
-
-  /**
-   * Liefert den Dateiauswahl-Dialog fuer die Browse-Aktion.
-   * @see JFileChooser
-   */
-  public JFileChooser getFileChooser() {
-    return fileChooser;
-  }
-
-  /**
-   * Liefert das ein {@link File}-Objekt zu der Text-Eingabe (Dateipfad)
-   * der Option.
-   * @param objectStr Objekt-String
-   */
-  public File convertFromString(String objectStr) {
-    return objectStr == null || objectStr.trim().equals("") ? null : new File(objectStr);
-  }
-
-  /**
-   * Liefert den kompletten Datei-Pfad fuer die durch die Eingabe-Option
-   * repraesentierten {@link File}.
-   * @param object {@link File}-Instanz
-   * @return {@code null}, fall kein {@link File}-Objekt uebergeben wird
-   */
-  public String convertToString(Object object) {
-//    if ( !(object instanceof File) )
-//      return null;
-    return ((File)object).getAbsolutePath();
-  }
-
-  /**
-   * Implementiert die Browse-Aktion die ausgefuehrt wird, wenn der Button der
-   * Eingabe-Option gedrueckt wird. Oeffnet einen {@link JFileChooser}.
-   * @param actValue aktueller Wert der Eingabe-Option
-   * @return <code>null</code> falls die Browse-Aktion abgebrochen wird
-   */
-  public File performBrowse(Object actValue) {
-    fileChooser.setSelectedFile( (File)actValue );
-    int ret = -1;
-    if ( fileChooser.getDialogType() == JFileChooser.OPEN_DIALOG )
-      ret = fileChooser.showOpenDialog(this.getInputComponent());
-    else
-      ret = fileChooser.showSaveDialog(this.getInputComponent());
-    if ( ret  == JFileChooser.APPROVE_OPTION )
-      return fileChooser.getSelectedFile();
-    return (File)actValue;
-  }
-}
+  /**
+   * Erzeugt eine neue Eingabe-Option.
+   * @param label Beschreibung der Eingabe-Option
+   * @param inputNeeded bestimmt, ob eine Eingabe erforderlich ist
+   * @param defValue Standard-Wert der vorgeblendet wird
+   */
+  public FileInputOption(String label, boolean inputNeeded, File defValue) {
+    super(label,inputNeeded,/*defValue == null ? new File(".") :*/ defValue);
+  }
+
+  /**
+   * Erzeugt eine neue Eingabe-Option.
+   * @param label Beschreibung der Eingabe-Option
+   * @param inputNeeded bestimmt, ob eine Eingabe erforderlich ist
+   */
+  public FileInputOption(String label, boolean inputNeeded) {
+    this(label,inputNeeded,null);
+  }
+
+  /**
+   * Liefert den Wert, der in der Option eingegeben wurde. Prueft zuerst
+   * auf Gueltigkeit und ruft dann {@link #performGetValue()} auf.
+   * @return <code>null</code> wenn die aktuelle Eingabe nicht zulaessig ist
+   *         (siehe {@link #isInputValid()})
+   */
+  public File getValue() {
+    return (File)super.getValue();
+  }
+
+  /**
+   * Liefert den Dateiauswahl-Dialog fuer die Browse-Aktion.
+   * @see JFileChooser
+   */
+  public JFileChooser getFileChooser() {
+    return fileChooser;
+  }
+
+  /**
+   * Liefert das ein {@link File}-Objekt zu der Text-Eingabe (Dateipfad)
+   * der Option.
+   * @param objectStr Objekt-String
+   */
+  public File convertFromString(String objectStr) {
+    return objectStr == null || objectStr.trim().equals("") ? null : new File(objectStr);
+  }
+
+  /**
+   * Liefert den kompletten Datei-Pfad fuer die durch die Eingabe-Option
+   * repraesentierten {@link File}.
+   * @param object {@link File}-Instanz
+   * @return {@code null}, fall kein {@link File}-Objekt uebergeben wird
+   */
+  public String convertToString(Object object) {
+//    if ( !(object instanceof File) )
+//      return null;
+    return ((File)object).getAbsolutePath();
+  }
+
+  /**
+   * Implementiert die Browse-Aktion die ausgefuehrt wird, wenn der Button der
+   * Eingabe-Option gedrueckt wird. Oeffnet einen {@link JFileChooser}.
+   * @param actValue aktueller Wert der Eingabe-Option
+   * @return <code>null</code> falls die Browse-Aktion abgebrochen wird
+   */
+  public File performBrowse(Object actValue) {
+    fileChooser.setSelectedFile( (File)actValue );
+    int ret = -1;
+    if ( fileChooser.getDialogType() == JFileChooser.OPEN_DIALOG )
+      ret = fileChooser.showOpenDialog(this.getInputComponent());
+    else
+      ret = fileChooser.showSaveDialog(this.getInputComponent());
+    if ( ret  == JFileChooser.APPROVE_OPTION )
+      return fileChooser.getSelectedFile();
+    return (File)actValue;
+  }
+}

Modified: trunk/src/schmitzm/swing/InputCompass.java
===================================================================
--- trunk/src/schmitzm/swing/InputCompass.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/InputCompass.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,157 +1,175 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing;
-
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.awt.Point;
-import java.awt.event.MouseAdapter;
-import java.awt.event.MouseEvent;
-
-import javax.swing.JSpinner;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-
-
-// fuer Doku
-
-/**
- * Diese Komponente stellt eine Kompass-Nadel dar, deren Ausrichtung
- * (Nord = 0°; West = 90°) ueber die Maus eingestellt werden kann. Daneben
- * besitzt das Panel einen {@link JSpinner}, um den Kompass-Wert manuell
- * einzustellen.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class InputCompass extends Compass {
-  /** Spinner zum Einstellen der Kompass-Einstellung. */
-  protected JSpinner spinner = null;
-
-  /**
-   * Erzeugt einen neuen Kompass. Der Spinner wird unterhalb des Kompass
-   * angezeigt.
-   */
-  public InputCompass() {
-    this(0);
-  }
-
-  /**
-   * Erzeugt einen neuen Kompass. Der Spinner wird unterhalb des Kompass
-   * angezeigt.
-   * @param degree angezeigte Grad-Angabe (Nord = 0°, West = 90°)
-   */
-  public InputCompass(double degree) {
-    this(degree, true);
-  }
-
-  /**
-   * Erzeugt einen neuen Kompass. Wird {@code null} als Spinner-Position
-   * angegeben, wird KEIN Spinnter angezeigt!
-   * @param degree angezeigte Grad-Angabe (Nord = 0°, West = 90°)
-   * @param showSpinner wenn {@code false}, wird KEIN Spinner angezeigt
-   */
-  public InputCompass(double degree, boolean showSpinner) {
-    this(degree,showSpinner,null,null);
-  }
-
-  /**
-   * Erzeugt einen neuen Kompass. Wird {@code null} als Spinner-Position
-   * angegeben, wird KEIN Spinnter angezeigt!
-   * @param degree angezeigte Grad-Angabe (Nord = 0°, West = 90°)
-   * @param showSpinner wenn {@code false}, wird KEIN Spinner angezeigt
-   * @param compassConstr Layout-Constraints fuer den Kompass
-   * @param spinnerConstr Layout-Constraints fuer den Spinner
-   */
-  public InputCompass(double degree, boolean showSpinner, GridBagConstraints compassConstr, GridBagConstraints spinnerConstr) {
-    super(degree);
-
-    if ( showSpinner ) {
-      if ( compassConstr == null )
-        compassConstr = new GridBagConstraints(
-          0, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 30, 30);
-      if ( spinnerConstr == null )
-        spinnerConstr = new GridBagConstraints(
-          0, 1, 1, 1, 1.0, 0.0, GridBagConstraints.NORTH, GridBagConstraints.NONE, new Insets(5, 0, 0, 0), 30, 0);
-
-      this.remove( getCompassPane() );
-      this.setLayout( new GridBagLayout() );
-      this.add( getCompassPane(), compassConstr );
-
-      this.spinner = new JSpinner(new RotationSpinnerNumberModel(degree, 0, 360, 0.1, true));
-      this.spinner.setEditor( new JSpinner.NumberEditor(this.spinner,SwingUtil.getNumberFormatPattern(3)) );
-      SwingUtil.setPreferredWidth( spinner, 100 );
-      this.add( spinner, spinnerConstr );
-
-      // ActionListener auf Spinner, um Kompass (THIS) zu aktualisieren
-      this.spinner.addChangeListener( new ChangeListener() {
-        public void stateChanged(ChangeEvent e) {
-          double newValue = (Double)spinner.getValue();
-          if ( newValue != InputCompass.this.getValue() )
-            InputCompass.this.setValue(newValue);
-        }
-      });
-      // ActionListener auf Kompass (THIS), um Spinner zu aktualisieren
-      InputCompass.this.addChangeListener( new ChangeListener() {
-        public void stateChanged(ChangeEvent e) {
-          double newValue = InputCompass.this.getValue();
-          if ( newValue != (Double)spinner.getValue() )
-            spinner.setValue(newValue);
-        }
-      });
-    }
-
-    // Mouse-Listener fuer Kompass-Einstellung
-    MouseAdapter listener = new MouseAdapter() {
-      private boolean button1pressed = false;
-      public void mouseDragged(MouseEvent e) {
-        if ( button1pressed )
-          setDegreeForMousePosition(e.getPoint());
-      }
-      public void mousePressed(MouseEvent e) {
-        if ( e.getButton() == MouseEvent.BUTTON1 ) {
-          button1pressed = true;
-          setDegreeForMousePosition(e.getPoint());
-        }
-      }
-      public void mouseReleased(MouseEvent e) {
-        button1pressed = false;
-      }
-    };
-    getCompassPane().addMouseMotionListener( listener );
-    getCompassPane().addMouseListener( listener );
-  }
-
-  /**
-   * Setzt die Grad-Einstellung der Kompass-Nadel entsprechend einer
-   * Maus-Position
-   * @param p Maus-Position relativ zur Kompass-Komponente ((0/0) ist oben-links)
-   */
-  private void setDegreeForMousePosition(Point p) {
-    if ( !isEnabled() )
-      return;
-
-    int centerX = getCompassPane().getWidth()/2;
-    int centerY = getCompassPane().getHeight()/2;
-
-    // (0/0) von Komponente ist oben-links
-    int dx = p.x - centerX;
-    int dy = centerY - p.y;
-    // Distanz zwischen Klickpunkt und Mittelpunkt
-    double radius = Math.hypot( dx,dy );
-    double degree = Math.toDegrees( Math.asin( dy/radius ) );
-    if ( dx < 0 )
-      degree = 180 - degree;
-    // 0° = Norden; 90° = West
-    setValue( degree-90 );
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.Point;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+import javax.swing.JSpinner;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+
+// fuer Doku
+
+/**
+ * Diese Komponente stellt eine Kompass-Nadel dar, deren Ausrichtung
+ * (Nord = 0°; West = 90°) ueber die Maus eingestellt werden kann. Daneben
+ * besitzt das Panel einen {@link JSpinner}, um den Kompass-Wert manuell
+ * einzustellen.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class InputCompass extends Compass {
+  /** Spinner zum Einstellen der Kompass-Einstellung. */
+  protected JSpinner spinner = null;
+
+  /**
+   * Erzeugt einen neuen Kompass. Der Spinner wird unterhalb des Kompass
+   * angezeigt.
+   */
+  public InputCompass() {
+    this(0);
+  }
+
+  /**
+   * Erzeugt einen neuen Kompass. Der Spinner wird unterhalb des Kompass
+   * angezeigt.
+   * @param degree angezeigte Grad-Angabe (Nord = 0°, West = 90°)
+   */
+  public InputCompass(double degree) {
+    this(degree, true);
+  }
+
+  /**
+   * Erzeugt einen neuen Kompass. Wird {@code null} als Spinner-Position
+   * angegeben, wird KEIN Spinnter angezeigt!
+   * @param degree angezeigte Grad-Angabe (Nord = 0°, West = 90°)
+   * @param showSpinner wenn {@code false}, wird KEIN Spinner angezeigt
+   */
+  public InputCompass(double degree, boolean showSpinner) {
+    this(degree,showSpinner,null,null);
+  }
+
+  /**
+   * Erzeugt einen neuen Kompass. Wird {@code null} als Spinner-Position
+   * angegeben, wird KEIN Spinnter angezeigt!
+   * @param degree angezeigte Grad-Angabe (Nord = 0°, West = 90°)
+   * @param showSpinner wenn {@code false}, wird KEIN Spinner angezeigt
+   * @param compassConstr Layout-Constraints fuer den Kompass
+   * @param spinnerConstr Layout-Constraints fuer den Spinner
+   */
+  public InputCompass(double degree, boolean showSpinner, GridBagConstraints compassConstr, GridBagConstraints spinnerConstr) {
+    super(degree);
+
+    if ( showSpinner ) {
+      if ( compassConstr == null )
+        compassConstr = new GridBagConstraints(
+          0, 0, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 30, 30);
+      if ( spinnerConstr == null )
+        spinnerConstr = new GridBagConstraints(
+          0, 1, 1, 1, 1.0, 0.0, GridBagConstraints.NORTH, GridBagConstraints.NONE, new Insets(5, 0, 0, 0), 30, 0);
+
+      this.remove( getCompassPane() );
+      this.setLayout( new GridBagLayout() );
+      this.add( getCompassPane(), compassConstr );
+
+      this.spinner = new JSpinner(new RotationSpinnerNumberModel(degree, 0, 360, 0.1, true));
+      this.spinner.setEditor( new JSpinner.NumberEditor(this.spinner,SwingUtil.getNumberFormatPattern(3)) );
+      SwingUtil.setPreferredWidth( spinner, 100 );
+      this.add( spinner, spinnerConstr );
+
+      // ActionListener auf Spinner, um Kompass (THIS) zu aktualisieren
+      this.spinner.addChangeListener( new ChangeListener() {
+        public void stateChanged(ChangeEvent e) {
+          double newValue = (Double)spinner.getValue();
+          if ( newValue != InputCompass.this.getValue() )
+            InputCompass.this.setValue(newValue);
+        }
+      });
+      // ActionListener auf Kompass (THIS), um Spinner zu aktualisieren
+      InputCompass.this.addChangeListener( new ChangeListener() {
+        public void stateChanged(ChangeEvent e) {
+          double newValue = InputCompass.this.getValue();
+          if ( newValue != (Double)spinner.getValue() )
+            spinner.setValue(newValue);
+        }
+      });
+    }
+
+    // Mouse-Listener fuer Kompass-Einstellung
+    MouseAdapter listener = new MouseAdapter() {
+      private boolean button1pressed = false;
+      public void mouseDragged(MouseEvent e) {
+        if ( button1pressed )
+          setDegreeForMousePosition(e.getPoint());
+      }
+      public void mousePressed(MouseEvent e) {
+        if ( e.getButton() == MouseEvent.BUTTON1 ) {
+          button1pressed = true;
+          setDegreeForMousePosition(e.getPoint());
+        }
+      }
+      public void mouseReleased(MouseEvent e) {
+        button1pressed = false;
+      }
+    };
+    getCompassPane().addMouseMotionListener( listener );
+    getCompassPane().addMouseListener( listener );
+  }
+
+  /**
+   * Setzt die Grad-Einstellung der Kompass-Nadel entsprechend einer
+   * Maus-Position
+   * @param p Maus-Position relativ zur Kompass-Komponente ((0/0) ist oben-links)
+   */
+  private void setDegreeForMousePosition(Point p) {
+    if ( !isEnabled() )
+      return;
+
+    int centerX = getCompassPane().getWidth()/2;
+    int centerY = getCompassPane().getHeight()/2;
+
+    // (0/0) von Komponente ist oben-links
+    int dx = p.x - centerX;
+    int dy = centerY - p.y;
+    // Distanz zwischen Klickpunkt und Mittelpunkt
+    double radius = Math.hypot( dx,dy );
+    double degree = Math.toDegrees( Math.asin( dy/radius ) );
+    if ( dx < 0 )
+      degree = 180 - degree;
+    // 0° = Norden; 90° = West
+    setValue( degree-90 );
+  }
+}

Modified: trunk/src/schmitzm/swing/InputOption.java
===================================================================
--- trunk/src/schmitzm/swing/InputOption.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/InputOption.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,316 +1,334 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing;
-
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.event.FocusEvent;
-import java.awt.event.FocusListener;
-import java.util.Vector;
-
-import javax.swing.JComponent;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-
-import schmitzm.swing.event.InputOptionListener;
-
-/**
- * Diese Klasse stellt die allgemeine Oberklasse fuer eine Eingabe-Option
- * des {@link MultipleOptionPane} dar. Jede Option besteht aus einem
- * {@linkplain #descLabel Label} und einem {@linkplain #inpComp Eingabefeld}.
- * Die Art des Eingabefelds wird durch die Unterklassen spezifiziert.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public abstract class InputOption<E> extends JPanel {
-  /** Speichert eine Referenz auf die Eingabe-Option (<code>this</code>), damit
-   *  in inneren Klassen darauf referenziert werden kann. */
-  protected final Component OPTION_COMPONENT = this;
-  /** Speichert die Beschreibung der Option */
-  protected JLabel    descLabel = null;
-  /** Speichert die Eingabe-Komponente der Option. */
-  protected JComponent inpComp   = null;
-  /** Kann eine Fehlermeldung enthalten, wenn die Eingabe nicht
-   *  valide ist. Kann direkt von {@link #performIsInputValid()} befuellt
-   *  werden. Wird automatisch befuellt, wenn {@link #performIsInputValid()}
-   *  eine Exception wirft. */
-  protected String invalidInputMess = "";
-
-  private   boolean   inpNeeded = false;
-  private   Vector    listeners = new Vector();
-  private   E         oldValue  = null;
-
-  /**
-   * Erzeugt eine neue Eingabe-Option.
-   * @param label       Beschreibung (wird im Label angezeigt)
-   * @param inputNeeded gibt an, ob eine Eingabe in der Option erforderlich ist
-   */
-  public InputOption(String label, boolean inputNeeded) {
-    this(label,inputNeeded,false);
-  }
-
-  /**
-   * Erzeugt eine neue Eingabe-Option.
-   * @param label       Beschreibung (wird im Label angezeigt)
-   * @param inputNeeded gibt an, ob eine Eingabe in der Option erforderlich ist
-   * @param centerInputComp bestimmt, ob die Eingabe-Komponente (siehe {@link #createInputComponent()})
-   *                        ins Zentrum des {@link BorderLayout} gelegt wird)
-   */
-  public InputOption(String label, boolean inputNeeded, boolean centerInputComp) {
-    this.inpNeeded = inputNeeded;
-
-    // Darstellung des Containers erzeugen
-    setLayout(new BorderLayout());
-    descLabel = new JLabel(label);
-    inpComp   = createInputComponent();
-    inpComp.addFocusListener( new FocusListener() {
-      public void focusGained(FocusEvent e) {
-        oldValue = getValue();
-        fireFocusGained();
-      }
-      public void focusLost(FocusEvent e) {
-        fireFocusLost();
-        if ( oldValue == null && getValue() != null ||
-             oldValue != null && !oldValue.equals( getValue() ) )
-          fireOptionChanged(oldValue,getValue());
-      }
-    });
-
-    // Elemente dem Container hinzufuegen
-    if ( label != null ) {
-      add( descLabel, BorderLayout.NORTH );
-      add( inpComp, centerInputComp ? BorderLayout.CENTER : BorderLayout.SOUTH );
-    } else {
-      add( inpComp, centerInputComp ? BorderLayout.CENTER : BorderLayout.NORTH );
-    }
-    doLayout();
-  }
-
-  /**
-   * Deaktiviert die Option, in dem die Eingabe-Komponente deaktiviert wird.
-   */
-  public void setEnabled(boolean enabled) {
-    super.setEnabled(enabled);
-    inpComp.setEnabled(enabled);
-  }
-
-  /**
-   * Setzt den Hilfetext fuer Eingabe-Komponente und Beschreibungslabel.
-   * @param text Hilfe-Text
-   */
-  public void setToolTipText(String text) {
-    super.setToolTipText(text);
-    if ( inpComp != null )
-      inpComp.setToolTipText(text);
-    if ( descLabel != null )
-      descLabel.setToolTipText(text);
-  }
-
-  /**
-   * Setzt den Fokus auf das Eingabe-Feld der {@code InputOption}.
-   */
-  public void grabFocus() {
-    inpComp.grabFocus();
-  }
-
-  /**
-   * Liefert den Wert, der in der Option eingegeben wurde. Prueft zuerst
-   * auf Gueltigkeit und ruft dann {@link #performGetValue()} auf.
-   * @return <code>null</code> wenn die aktuelle Eingabe nicht zulaessig ist
-   *         (siehe {@link #isInputValid()})
-   */
-  public E getValue() {
-    if ( !isInputValid() )
-      return null;
-    return performGetValue();
-  }
-
-  /**
-   * Setzt einen neuen Wert, mit der die Eingabe-Option belegt wird.
-   * Ruft {@link #performSetValue(Object)} auf und bewirkt ein
-   * {@link InputOptionListener#optionChanged(Object,Object)} fuer alle
-   * angeschlossenen {@link InputOptionListener}, falls sich der Wert der
-   * Option geaendert hat.
-   * @param newValue neuer Wert
-   * @return <code>false</code> gdw. der Objekt-Typ fuer die Option nicht
-   *         zulaessig ist
-   */
-  public boolean setValue(E newValue) {
-    // alten Wert speichern
-    oldValue = getValue();
-    if ( !performSetValue(newValue) )
-      return false;
-    newValue = getValue();
-    if ( oldValue==null && newValue!=null || oldValue!=null && newValue==null || oldValue!=null && !oldValue.equals( newValue ) )
-      fireOptionChanged(oldValue,getValue());
-    return true;
-  }
-
-  /**
-   * Liefert die Beschreibung der Eingabe-Option.
-   */
-  public String getLabel() {
-    return descLabel.getText();
-  }
-
-  /**
-   * Prueft, ob fuer das Feld zwingend eine Eingabe erforderlich ist.
-   */
-  public boolean inputNeeded() {
-    return inpNeeded;
-  }
-
-  /**
-   * Bestimmt, ob fuer das Feld zwingend eine Eingabe erforderlich ist.
-   */
-  public void setInputNeeded(boolean inpNeeded) {
-    this.inpNeeded = inpNeeded;
-  }
-
-  /**
-   * Prueft, ob die Eingabe in dem Feld zulaessig ist. Die Implementierung
-   * prueft zuerst auf Leereingabe und ruft dann {@link #performIsInputValid()}
-   * auf.
-   * @return <code>false</code> falls die Option leer ist, aber eine Eingabe
-   *         erforderlich ist
-   */
-  public boolean isInputValid() {
-    // Leereingabe
-    if (  inputEmpty() )
-      return !inputNeeded();
-    try {
-      this.invalidInputMess = "";
-      return performIsInputValid();
-    } catch (Exception err) {
-      this.invalidInputMess = err.getMessage();
-      return false;
-    }
-  }
-
-  /**
-   * Liefert die letzte von {@link #isInputValid()} erzeugte
-   * Fehlermeldung.
-   */
-  public String getInvalidInputMessage() {
-    return invalidInputMess;
-  }
-
-  /**
-   * Prueft, ob das Feld eine Leereingabe beinhaltet.
-   * @see #performIsInputEmpty()
-   */
-  public boolean inputEmpty() {
-    return performIsInputEmpty();
-  }
-
-  /**
-   * Liefert eine Referenz auf die Eingabe-Komponente.<br>
-   * <b>Bemerke:</b><br>
-   * Uber diese Referenz sollte hoechsten ihr Layout beeinflusst werden, aber
-   * nicht ihr Verhalten, da ansonsten die Funktionalitaet der <code>InputOption</code>
-   * negativ beeinflusst werden kann!!
-   */
-  public JComponent getInputComponent() {
-    return inpComp;
-  }
-
-  /**
-   * Liefert eine Referenz auf das Beschreibungs-Label.<br>
-   * <b>Bemerke:</b><br>
-   * Uber diese Referenz sollte hoechsten das Layout beeinflusst werden, aber
-   * nicht das Verhalten, da ansonsten die Funktionalitaet der <code>InputOption</code>
-   * negativ beeinflusst werden kann!!
-   */
-  public JLabel getDescriptionLabel() {
-    return descLabel;
-  }
-
-  /**
-   * Erzeugt eine neue Instanz der Eingabe-Komponente. z.B. ein Text-Eingabefeld
-   * oder eine Combo-Box.
-   */
-  protected abstract JComponent createInputComponent();
-
-  /**
-   * Liefert den aktuellen Wert der Eingabe-Option.
-   */
-  protected abstract E performGetValue();
-
-  /**
-   * Setzt den aktuellen Wert der Eingabe-Option. Ist der Objekt-Typ fuer die
-   * Option nicht zulaessig, sollte nichts gemacht werden und <code>false</code>
-   * zurueckgegeben werden.
-   * @param newValue neuer Wert
-   * @return <code>false</code> gdw. der Objekt-Typ fuer die Eingabe-Option
-   *         nicht zulaessig ist
-   */
-  protected abstract boolean performSetValue(E newValue);
-
-  /**
-   * Prueft, ob die aktuelle Eingabe leer ist.
-   */
-  protected abstract boolean performIsInputEmpty();
-
-  /**
-   * Prueft, ob die aktuelle Eingabe leer ist.
-   */
-  protected abstract boolean performIsInputValid();
-
-  /**
-   * Fuegt der Eingabeoption einen Listener hinzu.
-   * @param l neuer Listener
-   */
-  public void addInputOptionListener(InputOptionListener l) {
-    listeners.add(l);
-  }
-
-  /**
-   * Entfernt einen Listener von der Eingabeoption.
-   * @param l zu entfernender Listener
-   */
-  public void removeInputOptionListener(InputOptionListener l) {
-    listeners.remove(l);
-  }
-
-  /**
-   * Informiert alle {@link InputOptionListener}, dass die Eingabe-Option
-   * den Fokus erhalten hat.
-   */
-  protected void fireFocusGained() {
-    for (int i=0; i<listeners.size(); i++)
-      if ( listeners.elementAt(i) instanceof InputOptionListener )
-        ((InputOptionListener)listeners.elementAt(i)).optionGainedFocus(this);
-  }
-
-  /**
-   * Informiert alle {@link InputOptionListener}, dass die Eingabe-Option
-   * den Fokus verloren hat.
-   */
-  protected void fireFocusLost() {
-    for (int i=0; i<listeners.size(); i++)
-      if ( listeners.elementAt(i) instanceof InputOptionListener )
-        ((InputOptionListener)listeners.elementAt(i)).optionLostFocus(this);
-  }
-
-  /**
-   * Informiert alle {@link InputOptionListener}, dass sich der Wert der
-   * Eingabeoption geaendert hat.
-   * @param oldValue alter Optionswert
-   * @param newValue neuer Optionswert
-   */
-  protected void fireOptionChanged(Object oldValue, Object newValue) {
-    for (int i=0; i<listeners.size(); i++)
-      if ( listeners.elementAt(i) instanceof InputOptionListener )
-        ((InputOptionListener)listeners.elementAt(i)).optionChanged(this,oldValue,newValue);
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.event.FocusEvent;
+import java.awt.event.FocusListener;
+import java.util.Vector;
+
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+import schmitzm.swing.event.InputOptionListener;
+
+/**
+ * Diese Klasse stellt die allgemeine Oberklasse fuer eine Eingabe-Option
+ * des {@link MultipleOptionPane} dar. Jede Option besteht aus einem
+ * {@linkplain #descLabel Label} und einem {@linkplain #inpComp Eingabefeld}.
+ * Die Art des Eingabefelds wird durch die Unterklassen spezifiziert.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public abstract class InputOption<E> extends JPanel {
+  /** Speichert eine Referenz auf die Eingabe-Option (<code>this</code>), damit
+   *  in inneren Klassen darauf referenziert werden kann. */
+  protected final Component OPTION_COMPONENT = this;
+  /** Speichert die Beschreibung der Option */
+  protected JLabel    descLabel = null;
+  /** Speichert die Eingabe-Komponente der Option. */
+  protected JComponent inpComp   = null;
+  /** Kann eine Fehlermeldung enthalten, wenn die Eingabe nicht
+   *  valide ist. Kann direkt von {@link #performIsInputValid()} befuellt
+   *  werden. Wird automatisch befuellt, wenn {@link #performIsInputValid()}
+   *  eine Exception wirft. */
+  protected String invalidInputMess = "";
+
+  private   boolean   inpNeeded = false;
+  private   Vector    listeners = new Vector();
+  private   E         oldValue  = null;
+
+  /**
+   * Erzeugt eine neue Eingabe-Option.
+   * @param label       Beschreibung (wird im Label angezeigt)
+   * @param inputNeeded gibt an, ob eine Eingabe in der Option erforderlich ist
+   */
+  public InputOption(String label, boolean inputNeeded) {
+    this(label,inputNeeded,false);
+  }
+
+  /**
+   * Erzeugt eine neue Eingabe-Option.
+   * @param label       Beschreibung (wird im Label angezeigt)
+   * @param inputNeeded gibt an, ob eine Eingabe in der Option erforderlich ist
+   * @param centerInputComp bestimmt, ob die Eingabe-Komponente (siehe {@link #createInputComponent()})
+   *                        ins Zentrum des {@link BorderLayout} gelegt wird)
+   */
+  public InputOption(String label, boolean inputNeeded, boolean centerInputComp) {
+    this.inpNeeded = inputNeeded;
+
+    // Darstellung des Containers erzeugen
+    setLayout(new BorderLayout());
+    descLabel = new JLabel(label);
+    inpComp   = createInputComponent();
+    inpComp.addFocusListener( new FocusListener() {
+      public void focusGained(FocusEvent e) {
+        oldValue = getValue();
+        fireFocusGained();
+      }
+      public void focusLost(FocusEvent e) {
+        fireFocusLost();
+        if ( oldValue == null && getValue() != null ||
+             oldValue != null && !oldValue.equals( getValue() ) )
+          fireOptionChanged(oldValue,getValue());
+      }
+    });
+
+    // Elemente dem Container hinzufuegen
+    if ( label != null ) {
+      add( descLabel, BorderLayout.NORTH );
+      add( inpComp, centerInputComp ? BorderLayout.CENTER : BorderLayout.SOUTH );
+    } else {
+      add( inpComp, centerInputComp ? BorderLayout.CENTER : BorderLayout.NORTH );
+    }
+    doLayout();
+  }
+
+  /**
+   * Deaktiviert die Option, in dem die Eingabe-Komponente deaktiviert wird.
+   */
+  public void setEnabled(boolean enabled) {
+    super.setEnabled(enabled);
+    inpComp.setEnabled(enabled);
+  }
+
+  /**
+   * Setzt den Hilfetext fuer Eingabe-Komponente und Beschreibungslabel.
+   * @param text Hilfe-Text
+   */
+  public void setToolTipText(String text) {
+    super.setToolTipText(text);
+    if ( inpComp != null )
+      inpComp.setToolTipText(text);
+    if ( descLabel != null )
+      descLabel.setToolTipText(text);
+  }
+
+  /**
+   * Setzt den Fokus auf das Eingabe-Feld der {@code InputOption}.
+   */
+  public void grabFocus() {
+    inpComp.grabFocus();
+  }
+
+  /**
+   * Liefert den Wert, der in der Option eingegeben wurde. Prueft zuerst
+   * auf Gueltigkeit und ruft dann {@link #performGetValue()} auf.
+   * @return <code>null</code> wenn die aktuelle Eingabe nicht zulaessig ist
+   *         (siehe {@link #isInputValid()})
+   */
+  public E getValue() {
+    if ( !isInputValid() )
+      return null;
+    return performGetValue();
+  }
+
+  /**
+   * Setzt einen neuen Wert, mit der die Eingabe-Option belegt wird.
+   * Ruft {@link #performSetValue(Object)} auf und bewirkt ein
+   * {@link InputOptionListener#optionChanged(Object,Object)} fuer alle
+   * angeschlossenen {@link InputOptionListener}, falls sich der Wert der
+   * Option geaendert hat.
+   * @param newValue neuer Wert
+   * @return <code>false</code> gdw. der Objekt-Typ fuer die Option nicht
+   *         zulaessig ist
+   */
+  public boolean setValue(E newValue) {
+    // alten Wert speichern
+    oldValue = getValue();
+    if ( !performSetValue(newValue) )
+      return false;
+    newValue = getValue();
+    if ( oldValue==null && newValue!=null || oldValue!=null && newValue==null || oldValue!=null && !oldValue.equals( newValue ) )
+      fireOptionChanged(oldValue,getValue());
+    return true;
+  }
+
+  /**
+   * Liefert die Beschreibung der Eingabe-Option.
+   */
+  public String getLabel() {
+    return descLabel.getText();
+  }
+
+  /**
+   * Prueft, ob fuer das Feld zwingend eine Eingabe erforderlich ist.
+   */
+  public boolean inputNeeded() {
+    return inpNeeded;
+  }
+
+  /**
+   * Bestimmt, ob fuer das Feld zwingend eine Eingabe erforderlich ist.
+   */
+  public void setInputNeeded(boolean inpNeeded) {
+    this.inpNeeded = inpNeeded;
+  }
+
+  /**
+   * Prueft, ob die Eingabe in dem Feld zulaessig ist. Die Implementierung
+   * prueft zuerst auf Leereingabe und ruft dann {@link #performIsInputValid()}
+   * auf.
+   * @return <code>false</code> falls die Option leer ist, aber eine Eingabe
+   *         erforderlich ist
+   */
+  public boolean isInputValid() {
+    // Leereingabe
+    if (  inputEmpty() )
+      return !inputNeeded();
+    try {
+      this.invalidInputMess = "";
+      return performIsInputValid();
+    } catch (Exception err) {
+      this.invalidInputMess = err.getMessage();
+      return false;
+    }
+  }
+
+  /**
+   * Liefert die letzte von {@link #isInputValid()} erzeugte
+   * Fehlermeldung.
+   */
+  public String getInvalidInputMessage() {
+    return invalidInputMess;
+  }
+
+  /**
+   * Prueft, ob das Feld eine Leereingabe beinhaltet.
+   * @see #performIsInputEmpty()
+   */
+  public boolean inputEmpty() {
+    return performIsInputEmpty();
+  }
+
+  /**
+   * Liefert eine Referenz auf die Eingabe-Komponente.<br>
+   * <b>Bemerke:</b><br>
+   * Uber diese Referenz sollte hoechsten ihr Layout beeinflusst werden, aber
+   * nicht ihr Verhalten, da ansonsten die Funktionalitaet der <code>InputOption</code>
+   * negativ beeinflusst werden kann!!
+   */
+  public JComponent getInputComponent() {
+    return inpComp;
+  }
+
+  /**
+   * Liefert eine Referenz auf das Beschreibungs-Label.<br>
+   * <b>Bemerke:</b><br>
+   * Uber diese Referenz sollte hoechsten das Layout beeinflusst werden, aber
+   * nicht das Verhalten, da ansonsten die Funktionalitaet der <code>InputOption</code>
+   * negativ beeinflusst werden kann!!
+   */
+  public JLabel getDescriptionLabel() {
+    return descLabel;
+  }
+
+  /**
+   * Erzeugt eine neue Instanz der Eingabe-Komponente. z.B. ein Text-Eingabefeld
+   * oder eine Combo-Box.
+   */
+  protected abstract JComponent createInputComponent();
+
+  /**
+   * Liefert den aktuellen Wert der Eingabe-Option.
+   */
+  protected abstract E performGetValue();
+
+  /**
+   * Setzt den aktuellen Wert der Eingabe-Option. Ist der Objekt-Typ fuer die
+   * Option nicht zulaessig, sollte nichts gemacht werden und <code>false</code>
+   * zurueckgegeben werden.
+   * @param newValue neuer Wert
+   * @return <code>false</code> gdw. der Objekt-Typ fuer die Eingabe-Option
+   *         nicht zulaessig ist
+   */
+  protected abstract boolean performSetValue(E newValue);
+
+  /**
+   * Prueft, ob die aktuelle Eingabe leer ist.
+   */
+  protected abstract boolean performIsInputEmpty();
+
+  /**
+   * Prueft, ob die aktuelle Eingabe leer ist.
+   */
+  protected abstract boolean performIsInputValid();
+
+  /**
+   * Fuegt der Eingabeoption einen Listener hinzu.
+   * @param l neuer Listener
+   */
+  public void addInputOptionListener(InputOptionListener l) {
+    listeners.add(l);
+  }
+
+  /**
+   * Entfernt einen Listener von der Eingabeoption.
+   * @param l zu entfernender Listener
+   */
+  public void removeInputOptionListener(InputOptionListener l) {
+    listeners.remove(l);
+  }
+
+  /**
+   * Informiert alle {@link InputOptionListener}, dass die Eingabe-Option
+   * den Fokus erhalten hat.
+   */
+  protected void fireFocusGained() {
+    for (int i=0; i<listeners.size(); i++)
+      if ( listeners.elementAt(i) instanceof InputOptionListener )
+        ((InputOptionListener)listeners.elementAt(i)).optionGainedFocus(this);
+  }
+
+  /**
+   * Informiert alle {@link InputOptionListener}, dass die Eingabe-Option
+   * den Fokus verloren hat.
+   */
+  protected void fireFocusLost() {
+    for (int i=0; i<listeners.size(); i++)
+      if ( listeners.elementAt(i) instanceof InputOptionListener )
+        ((InputOptionListener)listeners.elementAt(i)).optionLostFocus(this);
+  }
+
+  /**
+   * Informiert alle {@link InputOptionListener}, dass sich der Wert der
+   * Eingabeoption geaendert hat.
+   * @param oldValue alter Optionswert
+   * @param newValue neuer Optionswert
+   */
+  protected void fireOptionChanged(Object oldValue, Object newValue) {
+    for (int i=0; i<listeners.size(); i++)
+      if ( listeners.elementAt(i) instanceof InputOptionListener )
+        ((InputOptionListener)listeners.elementAt(i)).optionChanged(this,oldValue,newValue);
+  }
+
+}

Modified: trunk/src/schmitzm/swing/JPanel.java
===================================================================
--- trunk/src/schmitzm/swing/JPanel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/JPanel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,79 +1,108 @@
-package schmitzm.swing;
-
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.FlowLayout;
-import java.awt.LayoutManager;
-
-/**
- * Diese Klasse erweitert das {@link javax.swing.JPanel} aus Standard-Java um
- * einige (nuetzliche) Funktionen.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class JPanel extends javax.swing.JPanel {
-  /**
-   * Erzeugt ein neues Panel.
-   * @param layout {@link LayoutManager} fuer das Panel
-   * @param isDoubleBuffered Flag, ob zusaetzlicher Speicher verwendet werden soll um
-   *        flicker-freie Updates zu gewaehrleisten
-   */
-  public JPanel(LayoutManager layout, boolean isDoubleBuffered) {
-    super(layout, isDoubleBuffered);
-  }
-
-  /**
-   * Erzeugt ein neues Panel.
-   * @param layout {@link LayoutManager} fuer das Panel
-   */
-  public JPanel(LayoutManager layout) {
-    super(layout);
-  }
-
-  /**
-   * Erzeugt ein neues Panel mit einem {@link FlowLayout}.
-   * @param isDoubleBuffered Flag, ob zusaetzlicher Speicher verwendet werden soll um
-   *        flicker-freie Updates zu gewaehrleisten
-   */
-  public JPanel(boolean isDoubleBuffered) {
-    super(isDoubleBuffered);
-  }
-
-  /**
-   * Erzeugt ein neues Panel mit einem {@link FlowLayout}.
-   */
-  public JPanel() {
-    super();
-  }
-
-  /**
-   * Aktiviert und deaktiviert alle Komponenten des Panels.
-   */
-  @Override
-  public void setEnabled(boolean enabled) {
-    super.setEnabled(enabled);
-    for (Component c : getComponents())
-      c.setEnabled(enabled);
-  }
-
-  /**
-   * Setzt die Hintergrund-Farbe der Komponente und optional die der
-   * untergeordneten Komponenten
-   * @param color neue Hintergrund-Farbe
-   * @param components bestimmt, ob auch die Hintergrundfarbe der Unterkomponenten
-   *        gesetzt werden soll
-   */
-  public void setBackground(Color color, boolean components) {
-    // Hintergrund von Panel selbst setzen
-    super.setBackground(color);
-    // wenn rekursive Verarbeitung, dann auch den Hintergrund
-    // der Componenten aendern
-    if ( components )
-      for ( Component c : getComponents() )
-        if ( c instanceof JPanel )
-          ((JPanel)c).setBackground(color,components);
-        else
-          c.setBackground(color);
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.FlowLayout;
+import java.awt.LayoutManager;
+
+/**
+ * Diese Klasse erweitert das {@link javax.swing.JPanel} aus Standard-Java um
+ * einige (nuetzliche) Funktionen.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class JPanel extends javax.swing.JPanel {
+  /**
+   * Erzeugt ein neues Panel.
+   * @param layout {@link LayoutManager} fuer das Panel
+   * @param isDoubleBuffered Flag, ob zusaetzlicher Speicher verwendet werden soll um
+   *        flicker-freie Updates zu gewaehrleisten
+   */
+  public JPanel(LayoutManager layout, boolean isDoubleBuffered) {
+    super(layout, isDoubleBuffered);
+  }
+
+  /**
+   * Erzeugt ein neues Panel.
+   * @param layout {@link LayoutManager} fuer das Panel
+   */
+  public JPanel(LayoutManager layout) {
+    super(layout);
+  }
+
+  /**
+   * Erzeugt ein neues Panel mit einem {@link FlowLayout}.
+   * @param isDoubleBuffered Flag, ob zusaetzlicher Speicher verwendet werden soll um
+   *        flicker-freie Updates zu gewaehrleisten
+   */
+  public JPanel(boolean isDoubleBuffered) {
+    super(isDoubleBuffered);
+  }
+
+  /**
+   * Erzeugt ein neues Panel mit einem {@link FlowLayout}.
+   */
+  public JPanel() {
+    super();
+  }
+
+  /**
+   * Aktiviert und deaktiviert alle Komponenten des Panels.
+   */
+  @Override
+  public void setEnabled(boolean enabled) {
+    super.setEnabled(enabled);
+    for (Component c : getComponents())
+      c.setEnabled(enabled);
+  }
+
+  /**
+   * Setzt die Hintergrund-Farbe der Komponente und optional die der
+   * untergeordneten Komponenten
+   * @param color neue Hintergrund-Farbe
+   * @param components bestimmt, ob auch die Hintergrundfarbe der Unterkomponenten
+   *        gesetzt werden soll
+   */
+  public void setBackground(Color color, boolean components) {
+    // Hintergrund von Panel selbst setzen
+    super.setBackground(color);
+    // wenn rekursive Verarbeitung, dann auch den Hintergrund
+    // der Componenten aendern
+    if ( components )
+      for ( Component c : getComponents() )
+        if ( c instanceof JPanel )
+          ((JPanel)c).setBackground(color,components);
+        else
+          c.setBackground(color);
+  }
+
+}

Modified: trunk/src/schmitzm/swing/ManualInputOption.java
===================================================================
--- trunk/src/schmitzm/swing/ManualInputOption.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/ManualInputOption.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,301 +1,319 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+import javax.swing.JTextField;
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+/**
+ * Diese Klasse stellt eine manuelle Eingabe-Option fuer das {@link MultipleOptionPane}
+ * dar. Die Eingabe erfolgt ueber ein {@link JTextField}. Ausser der
+ * "Input-Needed"-Restriktion, werden keine weiteren Anforderungen an die
+ * Eingabe gestellt. Die Klasse kann nicht direkt instanziiert werden.
+ * Statt dessen sind die eingebetteten Klassen
+ * <ul>
+ * <li>{@link ManualInputOption.Text    ManualInputOption.Text}</li>
+ * <li>{@link ManualInputOption.Integer ManualInputOption.Integer}</li>
+ * <li>{@link ManualInputOption.Double  ManualInputOption.Double}</li>
+ * </ul>
+ * zu verwenden.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class ManualInputOption extends InputOption {
+  /**
+   * Erzeugt eine neue Eingabe-Option.
+   * @param label       Beschreibung
+   * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
+   * @param defValue    Wert der im Textfeld vorgeblendet wird
+   */
+  protected ManualInputOption(String label, boolean inputNeeded, Object defValue) {
+    super(label,inputNeeded);
+    ((JTextField)inpComp).setText( defValue != null ? defValue.toString() : "");
+  }
 
-package schmitzm.swing;
-
-import javax.swing.JTextField;
-
-/**
- * Diese Klasse stellt eine manuelle Eingabe-Option fuer das {@link MultipleOptionPane}
- * dar. Die Eingabe erfolgt ueber ein {@link JTextField}. Ausser der
- * "Input-Needed"-Restriktion, werden keine weiteren Anforderungen an die
- * Eingabe gestellt. Die Klasse kann nicht direkt instanziiert werden.
- * Statt dessen sind die eingebetteten Klassen
- * <ul>
- * <li>{@link ManualInputOption.Text    ManualInputOption.Text}</li>
- * <li>{@link ManualInputOption.Integer ManualInputOption.Integer}</li>
- * <li>{@link ManualInputOption.Double  ManualInputOption.Double}</li>
- * </ul>
- * zu verwenden.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class ManualInputOption extends InputOption {
-  /**
-   * Erzeugt eine neue Eingabe-Option.
-   * @param label       Beschreibung
-   * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
-   * @param defValue    Wert der im Textfeld vorgeblendet wird
-   */
-  protected ManualInputOption(String label, boolean inputNeeded, Object defValue) {
-    super(label,inputNeeded);
-    ((JTextField)inpComp).setText( defValue != null ? defValue.toString() : "");
-  }
-
-  /**
-   * Erzeugt eine neue Instanz von {@link JTextField}.
-   */
-  protected JTextField createInputComponent() {
-    return new JTextField();
-  }
-
-  /**
-   * Liefert immer <code>true</code>, da keine speziellen Anforderungen
-   * an die Text-Eingabe gestellt werden.
-   */
-  protected boolean performIsInputValid() {
-    return true;
-  }
-
-  /**
-   * Prueft, ob im Eingabefeld ein Leerstring eingegeben wurde.
-   */
-  protected boolean performIsInputEmpty() {
-    return ((JTextField)inpComp).getText().trim().equals("");
-  }
-
-  /**
-   * Liefert die aktuelle Eingabe im {@link JTextField}.
-   */
-  protected Object performGetValue() {
-    return ((JTextField)inpComp).getText();
-  }
-
-  /**
-   * Setzt die aktuelle Eingabe im {@link JTextField}.
-   * @param newValue neuer Wert (muss vom Typ {@link String} sein!)
-   * @return <code>false</code> wenn kein {@link String} uebergeben wird
-   */
-  protected boolean performSetValue(Object newValue) {
-    if ( newValue == null )
-      newValue = "";
-    if ( !(newValue instanceof String) )
-      return false;
-    ((JTextField)inpComp).setText((String)newValue);
-    return true;
-  }
-
-  /**
-   * Diese Klasse stellt eine Eingabe-Option dar, in der ein beliebigen Text
-   * eingegeben werden kann.
-   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-   * @version 1.0
-   */
-  public static class Text extends ManualInputOption {
-    /**
-     * Erzeugt eine neue Eingabe-Option.
-     * @param label       Beschreibung
-     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
-     * @param defValue    Wert der im Textfeld vorgeblendet wird
-     */
-    public Text(String label, boolean inputNeeded, String defValue) {
-      super(label,inputNeeded,defValue);
-    }
-
-    /**
-     * Erzeugt eine neue Eingabe-Option.
-     * @param label       Beschreibung
-     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
-     */
-    public Text(String label, boolean inputNeeded) {
-      this(label,inputNeeded,"");
-    }
-
-    /**
-     * Erzeugt eine neue Eingabe-Option, in der eine Eingabe zwingend erforderlich
-     * ist.
-     * @param label Beschreibung
-     */
-    public Text(String label) {
-      this(label,true,"");
-    }
-
-    /**
-     * Erzeugt eine neue Eingabe-Option, in der eine Eingabe zwingend erforderlich
-     * ist.
-     * @param label    Beschreibung
-     * @param defValue Wert der im Textfeld vorgeblendet wird
-     */
-    public Text(String label, String defValue) {
-      this(label,true,defValue);
-    }
-
-    /**
-     * Liefert den Wert, der in der Option eingegeben wurde. Prueft zuerst
-     * auf Gueltigkeit und ruft dann {@link #performGetValue()} auf.
-     * @return <code>null</code> wenn die aktuelle Eingabe nicht zulaessig ist
-     *         (siehe {@link #isInputValid()})
-     */
-    public String getValue() {
-      return (String)super.getValue();
-    }
-  }
-
-  /**
-   * Diese Klasse stellt eine Eingabe-Option dar, in der ein Integer-Zahlen
-   * eingegeben werden kann.
-   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-   * @version 1.0
-   */
-  public static class Integer extends ManualInputOption {
-    /**
-     * Erzeugt eine neue Eingabe-Option.
-     * @param label       Beschreibung
-     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
-     * @param defValue    Wert der im Textfeld vorgeblendet wird
-     */
-    public Integer(String label, boolean inputNeeded, int defValue) {
-      super(label,inputNeeded,String.valueOf(defValue));
-    }
-
-    /**
-     * Erzeugt eine neue Eingabe-Option. Auch wenn die leere Eingabe u.U.
-     * nicht zulaessig ist, wird ein Leerstring vorgeblendet.
-     * @param label       Beschreibung
-     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
-     */
-    public Integer(String label, boolean inputNeeded) {
-      super(label,inputNeeded,"");
-    }
-
-    /**
-     * Erzeugt eine neue Eingabe-Option, in der eine Eingabe zwingend erforderlich
-     * ist. Auch wenn die leere Eingabe u.U. nicht zulaessig ist, wird ein
-     * Leerstring vorgeblendet.
-     * @param label Beschreibung
-     */
-    public Integer(String label) {
-      super(label,true,"");
-    }
-
-    /**
-     * Erzeugt eine neue Eingabe-Option, in der eine Eingabe zwingend erforderlich
-     * ist.
-     * @param label    Beschreibung
-     * @param defValue Wert der im Textfeld vorgeblendet wird
-     */
-    public Integer(String label, int defValue) {
-      this(label,true,defValue);
-    }
-
-    /**
-     * Liefert den Wert, der in der Option eingegeben wurde. Prueft zuerst
-     * auf Gueltigkeit und ruft dann {@link #performGetValue()} auf.
-     * @return <code>null</code> wenn die aktuelle Eingabe nicht zulaessig ist
-     *         (siehe {@link #isInputValid()})
-     */
-    public java.lang.Integer getValue() {
-      return (java.lang.Integer)super.getValue();
-    }
-
-    /**
-     * Transformiert die Text-Eingabe in einen Integer.
-     * @return <code>null</code> falls das Eingabefeld leer ist.
-     */
-    protected java.lang.Integer performGetValue() {
-      if ( inputEmpty() )
-        return null;
-      return java.lang.Integer.parseInt(((JTextField)inpComp).getText());
-    }
-
-    /**
-     * Prueft, ob ein gueltiger Integer-Wert im Feld eingegeben wurde.
-     */
-    protected boolean performIsInputValid() {
-      try {
-        java.lang.Integer.parseInt(((JTextField)inpComp).getText());
-      } catch (NumberFormatException err) {
-        return false;
-      }
-      return super.performIsInputValid();
-    }
-  }
-
-  /**
-   * Diese Klasse stellt eine Eingabe-Option dar, in der ein Double-Zahlen
-   * eingegeben werden kann.
-   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-   * @version 1.0
-   */
-  public static class Double extends ManualInputOption {
-    /**
-     * Erzeugt eine neue Eingabe-Option.
-     * @param label       Beschreibung
-     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
-     * @param defValue    Wert der im Textfeld vorgeblendet wird
-     */
-    public Double(String label, boolean inputNeeded, double defValue) {
-      super(label,inputNeeded,String.valueOf(defValue));
-    }
-
-    /**
-     * Erzeugt eine neue Eingabe-Option. Auch wenn die leere Eingabe u.U.
-     * nicht zulaessig ist, wird ein Leerstring vorgeblendet.
-     * @param label       Beschreibung
-     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
-     */
-    public Double(String label, boolean inputNeeded) {
-      super(label,inputNeeded,"");
-    }
-
-    /**
-     * Erzeugt eine neue Eingabe-Option, in der eine Eingabe zwingend erforderlich
-     * ist. Auch wenn die leere Eingabe u.U. nicht zulaessig ist, wird ein
-     * Leerstring vorgeblendet.
-     * @param label Beschreibung
-     */
-    public Double(String label) {
-      super(label,true,"");
-    }
-
-    /**
-     * Erzeugt eine neue Eingabe-Option, in der eine Eingabe zwingend erforderlich
-     * ist.
-     * @param label    Beschreibung
-     * @param defValue Wert der im Textfeld vorgeblendet wird
-     */
-    public Double(String label, int defValue) {
-      this(label,true,defValue);
-    }
-
-    /**
-     * Liefert den Wert, der in der Option eingegeben wurde. Prueft zuerst
-     * auf Gueltigkeit und ruft dann {@link #performGetValue()} auf.
-     * @return <code>null</code> wenn die aktuelle Eingabe nicht zulaessig ist
-     *         (siehe {@link #isInputValid()})
-     */
-    public java.lang.Double getValue() {
-      return (java.lang.Double)super.getValue();
-    }
-
-    /**
-     * Transformiert die Text-Eingabe in einen Double.
-     * @return <code>null</code> falls das Eingabefeld leer ist.
-     */
-    protected java.lang.Double performGetValue() {
-      if ( inputEmpty() )
-        return null;
-      return java.lang.Double.parseDouble(((JTextField)inpComp).getText());
-    }
-
-    /**
-     * Prueft, ob ein gueltiger Double-Wert im Feld eingegeben wurde.
-     */
-    protected boolean performIsInputValid() {
-      try {
-        java.lang.Double.parseDouble(((JTextField)inpComp).getText());
-      } catch (NumberFormatException err) {
-        return false;
-      }
-      return super.performIsInputValid();
-    }
-  }
-}
+  /**
+   * Erzeugt eine neue Instanz von {@link JTextField}.
+   */
+  protected JTextField createInputComponent() {
+    return new JTextField();
+  }
+
+  /**
+   * Liefert immer <code>true</code>, da keine speziellen Anforderungen
+   * an die Text-Eingabe gestellt werden.
+   */
+  protected boolean performIsInputValid() {
+    return true;
+  }
+
+  /**
+   * Prueft, ob im Eingabefeld ein Leerstring eingegeben wurde.
+   */
+  protected boolean performIsInputEmpty() {
+    return ((JTextField)inpComp).getText().trim().equals("");
+  }
+
+  /**
+   * Liefert die aktuelle Eingabe im {@link JTextField}.
+   */
+  protected Object performGetValue() {
+    return ((JTextField)inpComp).getText();
+  }
+
+  /**
+   * Setzt die aktuelle Eingabe im {@link JTextField}.
+   * @param newValue neuer Wert (muss vom Typ {@link String} sein!)
+   * @return <code>false</code> wenn kein {@link String} uebergeben wird
+   */
+  protected boolean performSetValue(Object newValue) {
+    if ( newValue == null )
+      newValue = "";
+    if ( !(newValue instanceof String) )
+      return false;
+    ((JTextField)inpComp).setText((String)newValue);
+    return true;
+  }
+
+  /**
+   * Diese Klasse stellt eine Eingabe-Option dar, in der ein beliebigen Text
+   * eingegeben werden kann.
+   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+   * @version 1.0
+   */
+  public static class Text extends ManualInputOption {
+    /**
+     * Erzeugt eine neue Eingabe-Option.
+     * @param label       Beschreibung
+     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
+     * @param defValue    Wert der im Textfeld vorgeblendet wird
+     */
+    public Text(String label, boolean inputNeeded, String defValue) {
+      super(label,inputNeeded,defValue);
+    }
+
+    /**
+     * Erzeugt eine neue Eingabe-Option.
+     * @param label       Beschreibung
+     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
+     */
+    public Text(String label, boolean inputNeeded) {
+      this(label,inputNeeded,"");
+    }
+
+    /**
+     * Erzeugt eine neue Eingabe-Option, in der eine Eingabe zwingend erforderlich
+     * ist.
+     * @param label Beschreibung
+     */
+    public Text(String label) {
+      this(label,true,"");
+    }
+
+    /**
+     * Erzeugt eine neue Eingabe-Option, in der eine Eingabe zwingend erforderlich
+     * ist.
+     * @param label    Beschreibung
+     * @param defValue Wert der im Textfeld vorgeblendet wird
+     */
+    public Text(String label, String defValue) {
+      this(label,true,defValue);
+    }
+
+    /**
+     * Liefert den Wert, der in der Option eingegeben wurde. Prueft zuerst
+     * auf Gueltigkeit und ruft dann {@link #performGetValue()} auf.
+     * @return <code>null</code> wenn die aktuelle Eingabe nicht zulaessig ist
+     *         (siehe {@link #isInputValid()})
+     */
+    public String getValue() {
+      return (String)super.getValue();
+    }
+  }
+
+  /**
+   * Diese Klasse stellt eine Eingabe-Option dar, in der ein Integer-Zahlen
+   * eingegeben werden kann.
+   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+   * @version 1.0
+   */
+  public static class Integer extends ManualInputOption {
+    /**
+     * Erzeugt eine neue Eingabe-Option.
+     * @param label       Beschreibung
+     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
+     * @param defValue    Wert der im Textfeld vorgeblendet wird
+     */
+    public Integer(String label, boolean inputNeeded, int defValue) {
+      super(label,inputNeeded,String.valueOf(defValue));
+    }
+
+    /**
+     * Erzeugt eine neue Eingabe-Option. Auch wenn die leere Eingabe u.U.
+     * nicht zulaessig ist, wird ein Leerstring vorgeblendet.
+     * @param label       Beschreibung
+     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
+     */
+    public Integer(String label, boolean inputNeeded) {
+      super(label,inputNeeded,"");
+    }
+
+    /**
+     * Erzeugt eine neue Eingabe-Option, in der eine Eingabe zwingend erforderlich
+     * ist. Auch wenn die leere Eingabe u.U. nicht zulaessig ist, wird ein
+     * Leerstring vorgeblendet.
+     * @param label Beschreibung
+     */
+    public Integer(String label) {
+      super(label,true,"");
+    }
+
+    /**
+     * Erzeugt eine neue Eingabe-Option, in der eine Eingabe zwingend erforderlich
+     * ist.
+     * @param label    Beschreibung
+     * @param defValue Wert der im Textfeld vorgeblendet wird
+     */
+    public Integer(String label, int defValue) {
+      this(label,true,defValue);
+    }
+
+    /**
+     * Liefert den Wert, der in der Option eingegeben wurde. Prueft zuerst
+     * auf Gueltigkeit und ruft dann {@link #performGetValue()} auf.
+     * @return <code>null</code> wenn die aktuelle Eingabe nicht zulaessig ist
+     *         (siehe {@link #isInputValid()})
+     */
+    public java.lang.Integer getValue() {
+      return (java.lang.Integer)super.getValue();
+    }
+
+    /**
+     * Transformiert die Text-Eingabe in einen Integer.
+     * @return <code>null</code> falls das Eingabefeld leer ist.
+     */
+    protected java.lang.Integer performGetValue() {
+      if ( inputEmpty() )
+        return null;
+      return java.lang.Integer.parseInt(((JTextField)inpComp).getText());
+    }
+
+    /**
+     * Prueft, ob ein gueltiger Integer-Wert im Feld eingegeben wurde.
+     */
+    protected boolean performIsInputValid() {
+      try {
+        java.lang.Integer.parseInt(((JTextField)inpComp).getText());
+      } catch (NumberFormatException err) {
+        return false;
+      }
+      return super.performIsInputValid();
+    }
+  }
+
+  /**
+   * Diese Klasse stellt eine Eingabe-Option dar, in der ein Double-Zahlen
+   * eingegeben werden kann.
+   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+   * @version 1.0
+   */
+  public static class Double extends ManualInputOption {
+    /**
+     * Erzeugt eine neue Eingabe-Option.
+     * @param label       Beschreibung
+     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
+     * @param defValue    Wert der im Textfeld vorgeblendet wird
+     */
+    public Double(String label, boolean inputNeeded, double defValue) {
+      super(label,inputNeeded,String.valueOf(defValue));
+    }
+
+    /**
+     * Erzeugt eine neue Eingabe-Option. Auch wenn die leere Eingabe u.U.
+     * nicht zulaessig ist, wird ein Leerstring vorgeblendet.
+     * @param label       Beschreibung
+     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
+     */
+    public Double(String label, boolean inputNeeded) {
+      super(label,inputNeeded,"");
+    }
+
+    /**
+     * Erzeugt eine neue Eingabe-Option, in der eine Eingabe zwingend erforderlich
+     * ist. Auch wenn die leere Eingabe u.U. nicht zulaessig ist, wird ein
+     * Leerstring vorgeblendet.
+     * @param label Beschreibung
+     */
+    public Double(String label) {
+      super(label,true,"");
+    }
+
+    /**
+     * Erzeugt eine neue Eingabe-Option, in der eine Eingabe zwingend erforderlich
+     * ist.
+     * @param label    Beschreibung
+     * @param defValue Wert der im Textfeld vorgeblendet wird
+     */
+    public Double(String label, int defValue) {
+      this(label,true,defValue);
+    }
+
+    /**
+     * Liefert den Wert, der in der Option eingegeben wurde. Prueft zuerst
+     * auf Gueltigkeit und ruft dann {@link #performGetValue()} auf.
+     * @return <code>null</code> wenn die aktuelle Eingabe nicht zulaessig ist
+     *         (siehe {@link #isInputValid()})
+     */
+    public java.lang.Double getValue() {
+      return (java.lang.Double)super.getValue();
+    }
+
+    /**
+     * Transformiert die Text-Eingabe in einen Double.
+     * @return <code>null</code> falls das Eingabefeld leer ist.
+     */
+    protected java.lang.Double performGetValue() {
+      if ( inputEmpty() )
+        return null;
+      return java.lang.Double.parseDouble(((JTextField)inpComp).getText());
+    }
+
+    /**
+     * Prueft, ob ein gueltiger Double-Wert im Feld eingegeben wurde.
+     */
+    protected boolean performIsInputValid() {
+      try {
+        java.lang.Double.parseDouble(((JTextField)inpComp).getText());
+      } catch (NumberFormatException err) {
+        return false;
+      }
+      return super.performIsInputValid();
+    }
+  }
+}

Modified: trunk/src/schmitzm/swing/MultiSplitPane.java
===================================================================
--- trunk/src/schmitzm/swing/MultiSplitPane.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/MultiSplitPane.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,703 +1,722 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.swing;
-
-import java.awt.BorderLayout;
-import java.awt.Container;
-
-import javax.swing.JComponent;
-import javax.swing.JSplitPane;
-import javax.swing.border.Border;
-
-/**
- * <hr>
- * <small><i>Diese Klasse wurde urspruenglich 2002/2003 von <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- *            fuer die ADAGIOS-Java-Library (Universitaet Bonn) erstellt, 2009 in das
- *            SCHMITZM-Projekt uebernommen und teilweise erweitert.</i></small>
- * <hr>
- * Ein <code>MultiSplitPane</code> ist eine Menge von horizontal oder
- * vertikal angeordneten Containern.<br>
- * Die Groesse dieser <code>Container</code> kann durch den Benutzer manuell
- * veraendert werden, in dem er die Trennlinien ("Dividers") zwischen den
- * Containern verschiebt.<br>
- * Das <code>MultiSplitPane</code> ist implementiert als eine baumartige
- * Verschachtelung von <code>JSplitPane</code>-Objekten, in denen immer
- * genau zwei Komponenten hinterlegt werden koennen.<br>
- * Aus diesem Grund kann die Darstellung der Randbereiche recht
- * unregelmaessig erscheinen. Deshalb ist es sinnvoll, den Rand entweder
- * komplett auszuschalten (<code>setInnerBorder(null)</code>), oder einen
- * unsichtbaren Rand zu verwenden (<code>setInnerBorder( new EmptyBorder(..) )</code>.
- * Dies gilt vor allem, wenn man ein <code>MultiSplitPane</code> mit vielen
- * Containern verwendet (mehr als 6 oder 7).
- * @see javax.swing.JSplitPane
- * @see javax.swing.JComponent
- * @see #setInnerBorder(Border)
- * @see javax.swing.border.EmptyBorder
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- */
-public class MultiSplitPane extends JComponent {
-
-  public static final int HORIZONTAL_SPLIT = JSplitPane.HORIZONTAL_SPLIT;
-  public static final int VERTICAL_SPLIT   = JSplitPane.VERTICAL_SPLIT;
-
-  private Container[]    container     = null;
-  private SplitPaneTree  rootSplitPane = null;
-  private int            orientation   = HORIZONTAL_SPLIT;
-  private int            dividerSize   = 0;
-  private Border         innerBorder   = new JSplitPane().getBorder();
-
-  /**
-   * Erzeugt ein neues MultiSplitPane. Dieses muss aus mindestens
-   * 2 Containern bestehen. Diese werden horizontal angeordnet.
-   * @param compCount   Anzahl an Containern im MultiSplitPane
-   * @exception java.lang.IllegalArgumentException falls die
-   *            Container-Anzahl < 2 ist.
-   */
-  public MultiSplitPane(int compCount) {
-    this(compCount,HORIZONTAL_SPLIT);
-  }
-
-  /**
-   * Erzeugt ein neues MultiSplitPane. Dieses muss aus mindestens
-   * 2 Containern bestehen. Moegliche Orientierungen:
-   * <ul>
-   * <li><code>HORIZONTAL_SPLIT</code></li>
-   * <li><code>VERTICAL_SPLIT</code></li>
-   * </ul>
-   * @param compCount   Anzahl an Containern im MultiSplitPane
-   * @param orientation Orientierung des MultiSplitPane
-   * @exception java.lang.IllegalArgumentException falls die Orientierung
-   *            ungueltig ist oder die Container-Anzahl < 2 ist.
-   */
-  public MultiSplitPane(int compCount, int orientation) {
-    super();
-    this.setLayout( new BorderLayout() );
-
-    if (compCount < 2)
-      throw new IllegalArgumentException("MultiSplitPane must have at least 2 Components");
-    // erstmal nur die Orientierung checken, setzen folgt nachdem
-    // der SplitPaneTree aufgebaut ist
-    checkOrientation(orientation);
-
-    // Referenz auf die Container (der Effizienz wegen) nochmal
-    // in einer Liste speichern
-    container = new Container[compCount];
-    for (int i=0; i<container.length; i++) {
-      container[i] = new Container();
-      container[i].setLayout( new BorderLayout() );
-    }
-    rootSplitPane = new SplitPaneTree(container);
-    // Orientierung setzen
-    setOrientation(orientation);
-    // Basis-SplitPane im Haupt-Container einfuegen
-    this.add(rootSplitPane.getSplitPane());
-  }
-
-  /**
-   * Liefert die Anzahl an Komponenten, in die das SplitPane aufgeteilt ist.
-   */
-  public int getContainerCount() {
-    return container.length;
-  }
-
-  /**
-   * Liefert den Inhalt eine Teil-Panes.
-   * @param i    Index des Teil-Panes (von links/oben nach rechts/unten)
-   * @exception java.lang.ArrayIndexOutOfBoundsException falls ein ungueltiger
-   *            Index angegeben wird
-   */
-  public Container getContainer(int i) {
-    return container[i];
-  }
-
-  /**
-   * Setzt den Inhalt eine Teil-Panes.
-   * @param i    Index des Teil-Panes (von links/oben nach rechts/unten)
-   * @param cont neuer Inhalt des Teil-Panes
-   * @exception java.lang.ArrayIndexOutOfBoundsException falls ein ungueltiger
-   *            Index angegeben wird
-   */
-  public void setContainer(int i, Container cont) {
-    this.container[i] = cont;
-    rootSplitPane.setContainer(i,cont);
-  }
-
-  /**
-   * Liefert die Orientierung in der die Container des MultiSplitPanes
-   * angeordnet sind.
-   * @see #setOrientation(int)
-   */
-  public int getOrientation() {
-    return this.orientation;
-  }
-
-  /**
-   * Aendert die Orientierung des SplitPanes. Moegliche
-   * Orientierungen:
-   * <ul>
-   * <li><code>HORIZONTAL_SPLIT</code></li>
-   * <li><code>VERTICAL_SPLIT</code></li>
-   * </ul>
-   * @param orientation neue Orientierung
-   * @exception java.lang.IllegalArgumentException falls die Orientierung
-   *            ungueltig ist
-   * @see #getOrientation()
-   */
-  public void setOrientation(int orientation) {
-    checkOrientation(orientation);
-
-    final int o = orientation;
-    rootSplitPane.performAllSplitPanes(
-        new SplitPaneTreePerformer() {
-            public void performSplitPaneTree(SplitPaneTree tree) {
-              tree.getSplitPane().setOrientation(o);
-            }
-        }
-    );
-    this.orientation = orientation;
-  }
-
-  /**
-   * Checkt, ob die angegebene Orientierung gueltig ist. Andernfalls wird
-   * eine Exception geworfen.
-   * @param orientation Orientierung
-   * @exception java.lang.IllegalArgumentException falls die Orientierung
-   *            ungueltig ist
-   */
-  protected void checkOrientation(int orientation) {
-    if (orientation != HORIZONTAL_SPLIT &&
-        orientation != VERTICAL_SPLIT)
-      throw new IllegalArgumentException("HORIZONTAL_SPLIT or VERTICAL_SPLIT expected!!");
-  }
-
-  /**
-   * Liefert die Groesse des Dividers (in Pixeln).
-   */
-  public int getDividerSize() {
-    return dividerSize;
-  }
-
-  /**
-   * Setzt die Groesse der Divider-Balken. Die Darstellung des "laestigen"
-   * einpixligen Strichs laesst sich zwar verhindern, indem man die
-   * Divider-Groesse auf 0 setzt, leider sind dann aber auch die Groessen der
-   * einzelnen Container nicht mehr veraenderbar!!
-   * @param size Groesse in Pixeln
-   * @see #getDividerSize()
-   */
-  public void setDividerSize(int size) {
-    final int s = size;
-    rootSplitPane.performAllSplitPanes(
-        new SplitPaneTreePerformer() {
-            public void performSplitPaneTree(SplitPaneTree tree) {
-              tree.getSplitPane().setDividerSize(s);
-            }
-        }
-    );
-    this.dividerSize = size;
-  }
-
-  /**
-   * Liefert das gesetzte Gewicht eines Containers, mit dessen Anteil
-   * dieser bei einer Platzvergroesserung beruecksichtigt wird.
-   * @param i Index des Teil-Panes (von links/oben nach rechts/unten)
-   * @exception java.lang.ArrayIndexOutOfBoundsException falls ein ungueltiger
-   *            Index angegeben wird
-   * @see #setResizeWeigth(double[])
-   */
-  public double getResizeWeight(int i) {
-    // Teilbaum (JSplitPane) suchen, in dem der Container mit
-    // dem Index i abgelegt ist
-    SplitPaneTree tree = rootSplitPane.getSplitPaneTree(i);
-
-    // ResizeWeight-Anteil des SplitPanes
-    double splitPaneWeight = tree.getResizeWeight();
-    // Gewicht der linken Komponente (bezogen auf das eine SplitPane)
-    double weight = tree.getSplitPane().getResizeWeight();
-    // liegt der gesuchte Container im rechten Teil-Pane,
-    // muss das Gegengewicht genommen werden
-    if ( tree.getSplitPane().getLeftComponent() != getContainer(i) )
-      weight = 1 - weight;
-
-    return weight * splitPaneWeight;
-  }
-
-  /**
-   * Liefert die Gewichte aller Containers, mit deren Anteil diese bei
-   * einer Platzvergroesserung beruecksichtigt werden.
-   * @see #getResizeWeight(int)
-   * @see #setResizeWeigth(double[])
-   */
-  public double[] getResizeWeight() {
-    double[] weight = new double[ getContainerCount() ];
-    for (int i=0; i<weight.length; i++)
-      weight[i] = getResizeWeight(i);
-    return weight;
-  }
-
-  /**
-   * Setzt die Container-Gewichtungen, mit deren Anteil diese bei einer
-   * Platzvergroesserung beruecksichtigt werden. Bei der Angabe der
-   * Gewichte sind folgende Punkte zu beachten:
-   * <ul>
-   * <li>Die Summe der angegebenen Gewichte darf 1 nicht ueberschreiten.</li>
-   * <li>Es duerfen hoechstens so viele Gewichte angegeben werden, wie
-   *     Container im <code>MultiSplitPane</code> vorhanden sind.</li>
-   * <li>Werden genau so viele Gewichte angegeben, wie Container im
-   *     <code>MultiSplitPane</code> vorhanden sind, muss die Summe der
-   *     Gewichte 1 ergeben</li>
-   * <li>Werden weniger Gewichte als vorhandene Container angegeben, so wird
-   *     das restliche Gewicht gleichmaessig auf die uebrigen Container
-   *     verteilt.</li>
-   * </ul>
-   * @param weight neue Gewichte
-   * @exception java.lang.IllegalArgumentException falls eine der obigen
-   *            Bedingungen verletzt ist.
-   */
-  public void setResizeWeigth(double[] weight) {
-    if ( weight.length > getContainerCount() )
-      throw new IllegalArgumentException("Es duerfen hoechstens so viele Gewichte, wie Container angegeben werden!");
-
-    // Gewichte in einen Array kopieren, dessen Groesse genau der
-    // Anzahl an Containern entspricht
-    final double[] newWeight = new double[ getContainerCount() ];
-          double   weightSum = 0.0;
-
-    for (int i=0; i<newWeight.length; i++) {
-      if ( i<weight.length ) {
-        weightSum += weight[i]; // Gewichtssumme ermitteln
-        if ( weightSum > 1.0 )
-          throw new IllegalArgumentException("Die angegebnene Summe der Gewichte ist groesser als 1!!");
-        newWeight[i] = weight[i]; // vorhandenes Gewicht kopieren
-      }
-      else {
-        // Bei Angabe von zu wenig Gewichten, wird der Rest "gerecht"
-        // verteilt
-        newWeight[i] = (1-weightSum) / (newWeight.length - weight.length);
-      }
-    }
-
-    if ( weight.length == newWeight.length && weightSum < 1 )
-      throw new IllegalArgumentException("Werden Gewichte fuer alle Container angegeben, muss deren Summe 1 ergeben!!");
-
-    rootSplitPane.performAllSplitPanes(
-        new SplitPaneTreePerformer() {
-            private int contCounter = 0;
-
-            public void performSplitPaneTree(SplitPaneTree tree) {
-              // Beinhaltet das SplitPane einen (finalen) Container
-              // wird dessen neues Gewicht genommen, ansonsten das
-              // Gewicht des gesamten Teilbaums (dieses ist aufgrund
-              // des POSTORDER-Druchlaufs bereits neu berechnet!!)
-              double lWeight = ( !tree.isSplittedLeft() )  ? newWeight[contCounter++] : tree.getLeftResizeWeight();
-              double rWeight = ( !tree.isSplittedRight() ) ? newWeight[contCounter++] : tree.getRightResizeWeight();
-              // neues Gewicht fuer den Teilbaum neu setzen
-              tree.setResizeWeight( lWeight + rWeight );
-              // neues Gewicht fuer das Root-SplitPane des Teilbaum neu setzen
-              tree.getSplitPane().setResizeWeight( lWeight / tree.getResizeWeight() );
-            }
-        });
-  }
-
-  /**
-   * Liefert die Border des <code>MultiSplitPane</code>
-   */
-  public Border getInnerBorder() {
-    return this.innerBorder;
-  }
-
-  /**
-   * Setzt die Border fuer alle Container.
-   */
-  public void setInnerBorder(final Border border) {
-    rootSplitPane.performAllSplitPanes(
-        new SplitPaneTreePerformer() {
-            public void performSplitPaneTree(SplitPaneTree tree) {
-              tree.getSplitPane().setBorder(border);
-            }
-        });
-    this.innerBorder = border;
-  }
-
-  /////////////////////////////////////////////////////////////////////////
-  ///// Interface   SplitPaneTreePerformer                            /////
-  /////////////////////////////////////////////////////////////////////////
-  private interface SplitPaneTreePerformer {
-    public void performSplitPaneTree(SplitPaneTree tree);
-  }
-
-  /////////////////////////////////////////////////////////////////////////
-  ///// Klasse   SplitPaneTree                                        /////
-  /////////////////////////////////////////////////////////////////////////
-  private class SplitPaneTree {
-    private JSplitPane    splitPane    = null;
-    private int           contCount    = 0;
-    private SplitPaneTree leftTree     = null;
-    private SplitPaneTree rightTree    = null;
-    private double        resizeWeight = 0.0;
-
-    /**
-     * Interner Konstruktor zum Initialisieren ALLER Variablen.
-     */
-    private void init(JSplitPane splitPane, int contCount, double weight, SplitPaneTree left, SplitPaneTree right) {
-      this.splitPane    = splitPane;
-      this.contCount    = contCount;
-      this.resizeWeight = weight;
-      this.leftTree     = left;
-      this.rightTree    = right;
-    }
-
-    /**
-     * Interner Konstruktor zum Initialisieren eines (Teil-)Baums, der
-     * sowohl links, als auch rechts weiter geplittet ist.
-     */
-    private void initInner(JSplitPane splitPane, double weight, SplitPaneTree left, SplitPaneTree right) {
-      init(splitPane,left.getContainerCount()+right.getContainerCount(),weight,left,right);
-    }
-
-    /**
-     * Erzeugt einen neuen (Teil-)Baum, der sowohl links, als auch rechts
-     * weiter gesplittet ist. Beide Teil-Panes sind also weiter unterteilt.
-     * @param splitPane <code>JSplitPane</code> fuer das der (Teil-)Baum steht
-     * @param weight    Gewicht des Teilbaums bezogen auf den gesamten Baum
-     *                  (Anteil am neuen Platz, den die Container im Teilbaum
-     *                  erhalten, wenn sich das Pane vergroessert)
-     * @param left      linker Teilbaum
-     * @param right     rechter Teilbaum
-     */
-    public SplitPaneTree(JSplitPane splitPane, double weight, SplitPaneTree left, SplitPaneTree right) {
-      initInner(splitPane,weight,left,right);
-    }
-
-    /**
-     * Interner Konstruktor zum Initialisieren eines Blattes.
-     */
-    private void initLeaf(JSplitPane splitPane, double weight) {
-      init(splitPane,2,weight,null,null);
-    }
-
-    /**
-     * Erzeugt ein neues Blatt. Beide Teil-Panes enthalten also einen
-     * <code>Container</code> und sind nicht weiter gesplittet.
-     * @param splitPane <code>JSplitPane</code> fuer das der (Teil-)Baum steht
-     * @param weight    Gewicht des Teilbaums bezogen auf den gesamten Baum
-     *                  (Anteil am neuen Platz, den die Container im Teilbaum
-     *                  erhalten, wenn sich das Pane vergroessert)
-     */
-    public SplitPaneTree(JSplitPane splitPane, double weight) {
-      initLeaf(splitPane,weight);
-    }
-
-    /**
-     * Interner Konstruktor zum Initialisieren eines (Teil-)Baums, der
-     * links gesplittet ist und rechts ein Blatt hat.
-     */
-    private void initHalfLeaf(JSplitPane splitPane, double weight, SplitPaneTree left) {
-      init(splitPane,left.getContainerCount()+1,weight,left,null);
-    }
-
-    /**
-     * Erzeugt einen neuen (Teil-)Baum, der nach links gesplittet ist und rechts
-     * endet ("Halb-Blatt"). Das linke Teil-Pane ist also weiter unterteilt, waehrend im
-     * rechten Teil-Pane ein <code>Container</code> zu finden ist.
-     * @param splitPane <code>JSplitPane</code> fuer das der (Teil-)Baum steht
-     * @param weight    Gewicht des Teilbaums bezogen auf den gesamten Baum
-     *                  (Anteil am neuen Platz, den die Container im Teilbaum
-     *                  erhalten, wenn sich das Pane vergroessert)
-     * @param left      linker Teilbaum
-     */
-    public SplitPaneTree(JSplitPane splitPane, double weight, SplitPaneTree left) {
-      initHalfLeaf(splitPane,weight,left);
-    }
-
-    /**
-     * Erzeugt einen neuen Baum.
-     * @param container Container, die das SplitPane haben soll
-     * @param start     Index im <code>Container</code>-Array, bei dem
-     *                  begonnen wird (alle davor werden ignoriert)
-     * @param weight    Gewicht des Teilbaums bezogen auf den gesamten Baum
-     *                  (Anteil am neuen Platz, den die Container im Teilbaum
-     *                  erhalten, wenn sich das Pane vergroessert)
-     */
-    public SplitPaneTree(Container[] container, int start, int count, double weight) {
-//  System.out.println(start+"\t"+count+"\t"+weight);
-      if ( count < 2 )
-        throw new IllegalArgumentException("SplitPane must have at least 2 Containers");
-
-      if ( start + count -1 >= container.length )
-        throw new IllegalArgumentException("'count' too big for this start position in Container-Array");
-
-      this.splitPane = new JSplitPane();
-
-      // Aufteilung ermitteln
-      int rightCount  = count / 2;
-      int leftCount   = count - rightCount;
-      // Vergroesserungs-Gewichte ermitteln:
-      // --> Entsprechend der Aufteilung erhalten die beiden Teil-Panes
-      //     einen Anteil am Gesamt-Gewicht des SplitPanes
-      double rightWeight = weight/count * rightCount;
-      double leftWeight  = weight/count * leftCount;
-
-      // bei nur 2 Teil-Panes wird nicht mehr weiter gesplitten
-      // --> Blatt erzeugen
-      if ( leftCount == 1 && rightCount == 1 )
-        initLeaf(splitPane,weight);
-
-      // nur das linke Teil-Pane wird weitergesplittet
-      // --> Halb-Blatt erzeugen
-      if ( leftCount > 1 && rightCount == 1)
-        initHalfLeaf(splitPane,weight,new SplitPaneTree(container,start,leftCount,leftWeight));
-
-      // beider Teil-Panes werden weitergesplittet
-      // --> Inneren Knoten erzeugen
-      if ( leftCount > 1 && rightCount > 1)
-        initInner(splitPane,weight, new SplitPaneTree(container,start,leftCount,leftWeight),
-                                    new SplitPaneTree(container,start+leftCount,rightCount,rightWeight) );
-
-      // Das Split-Pane initialisieren, fuer das dieser Knoten steht
-//  System.out.println(start+"\t"+count+"\t"+isSplittedLeft()+"\t"+isSplittedRight());
-      if ( this.isSplittedLeft() )
-        this.splitPane.setLeftComponent( this.getLeftTree().getSplitPane() );
-      else
-        this.splitPane.setLeftComponent( container[ start ] );
-
-      if ( this.isSplittedRight() )
-        this.splitPane.setRightComponent( this.getRightTree().getSplitPane() );
-      else
-        this.splitPane.setRightComponent( container[ start+count-1 ] );
-
-      this.splitPane.setResizeWeight(leftWeight/weight);
-    }
-
-    /**
-     * Erzeugt einen neuen Baum.
-     * @param container Container, die das SplitPane haben soll
-     * @param start     Index im <code>Container</code>-Array, bei dem
-     *                  begonnen wird (alle davor werden ignoriert)
-     * @param weight    Gewicht des Teilbaums bezogen auf den gesamten Baum
-     *                  (Anteil am neuen Platz, den die Container im Teilbaum
-     *                  erhalten, wenn sich das Pane vergroessert)
-     */
-    public SplitPaneTree(Container[] container, int start, double weight) {
-      this(container,start,container.length - start,weight);
-    }
-
-    /**
-     * Erzeugt einen neuen Baum.
-     * @param container Container, die das SplitPane haben soll
-     */
-    public SplitPaneTree(Container[] container) {
-      this(container,0,1.0);
-    }
-
-    /**
-     * Liefert das <code>JSplitPane</code> fuer das der Knoten steht.
-     */
-    public JSplitPane getSplitPane() {
-      return splitPane;
-    }
-
-    /**
-     * Liefert die Anzahl an Containern, die im Teil-Baum vorhanden sind.
-     */
-    public int getContainerCount() {
-      return contCount;
-    }
-
-    /**
-     * Checkt, ob das linke (obere) Teil-Pane wiederum gesplittet ist
-     * (<code>true</code>) oder einen Container enthaelt (<code>false</code>).
-     */
-    public boolean isSplittedLeft() {
-      return getLeftTree() != null;
-    }
-
-    /**
-     * Liefert den linken Teilbaum des aktuellen Knoten.
-     * @return <code>null</code>, falls das linke (obere) Teil-Pane einen
-     *         Container enthaelt und nicht weiter gesplittet ist.
-     */
-    public SplitPaneTree getLeftTree() {
-      return leftTree;
-    }
-
-    /**
-     * Checkt, ob das rechte (untere) Teil-Pane wiederum gesplittet ist
-     * (<code>true</code>) oder einen Container enthaelt (<code>false</code>).
-     */
-    public boolean isSplittedRight() {
-      return getRightTree() != null;
-    }
-
-    /**
-     * Liefert den rechten Teilbaum des aktuellen Knoten.
-     * @return <code>null</code>, falls das rechte (untere) Teil-Pane einen
-     *         Container enthaelt und nicht weiter gesplittet ist.
-     */
-    public SplitPaneTree getRightTree() {
-      return rightTree;
-    }
-
-    /**
-     * Aendert den Gesamt-Anteil am neuen Platz, den die Container im (Teil-Baum)
-     * erhalten.<br>
-     * <b>Diese Methode sollte nur in einem kontrollierten Durchlauf durch
-     * alle Teilbaeume verwendet werden, in dem gewaehrleistet ist, dass
-     * mit der Aenderung des Gewichts auch die Gewichte der anderen Teilbaeume
-     * korrekt abgeaendert werden!! Die macht diese Methode naemlich
-     * <u>nicht</u> automatisch!!</b>
-     */
-    public void setResizeWeight(double weight) {
-      this.resizeWeight = weight;
-    }
-
-    /**
-     * Liefert den Anteil am gesamten neuen Platz, den die Container erhalten,
-     * die im (Teil-)Baums liegen.
-     */
-    public double getResizeWeight() {
-      return resizeWeight;
-    }
-
-    /**
-     * Liefert den Anteil am gesamten neuen Platz, den die Container erhalten,
-     * die im linken Teil-Baum (also im linken/oberen Teil-Pane) liegen.
-     */
-    public double getLeftResizeWeight() {
-      if ( isSplittedLeft() ) return getLeftTree().getResizeWeight();
-      return getSplitPane().getResizeWeight() * getResizeWeight();
-    }
-
-    /**
-     * Liefert den Anteil am gesamten neuen Platz, den die Container erhalten,
-     * die im rechten Teil-Baum (also im rechten/unteren Teil-Pane) liegen.
-     */
-    public double getRightResizeWeight() {
-      if ( isSplittedRight() ) return getRightTree().getResizeWeight();
-      return (1-getSplitPane().getResizeWeight()) * getResizeWeight();
-    }
-
-    /**
-     * Liefert den Container eines Blattes aus dem (Teil-)Baum. Dabei sind die
-     * Container (mit 0 beginnend) von links nach recht im Baum durchnummeriert.
-     * @param i Nummer des Containers
-     * @exception lava.lang.ArrayIndexOutOfBoundsException falls in dem Teilbaum
-     *            nicht genug Container vorhanden sind
-     */
-    public Container getContainer(int i) {
-      if ( i>= getContainerCount() )
-        throw new ArrayIndexOutOfBoundsException("not enough Containers in SplitPaneTree");
-
-      int leftCount = 0;
-      if ( isSplittedLeft() ) leftCount = getLeftTree().getContainerCount();
-
-      int rightCount = 0;
-      if ( isSplittedRight() ) rightCount = getRightTree().getContainerCount();
-
-      // erster Container gesucht und kein linker Teilbaum
-      // --> also Container im linken Teil-Pane ist der gesuchte
-      if ( i == 0 && leftCount == 0 )
-        return (Container)splitPane.getLeftComponent();
-      // letzter Container gesucht und kein rechter Teilbaum
-      // --> also Container im rechten Teil-Pane ist der gesuchte
-      if ( i == getContainerCount()-1 && rightCount == 0 )
-        return (Container)splitPane.getRightComponent();
-      // gesuchter Container liegt im linken Teil-Pane
-      if ( i < leftCount )
-        return getLeftTree().getContainer(i);
-      // gesuchter Container liegt im rechten Teil-Pane
-      return getRightTree().getContainer(i-leftCount);
-    }
-
-    /**
-     * Liefert den Container eines Blattes aus dem (Teil-)Baum. Dabei sind die
-     * Container (mit 0 beginnend) von links nach recht im Baum durchnummeriert.
-     * @param i Nummer des Containers
-     * @exception lava.lang.ArrayIndexOutOfBoundsException falls in dem Teilbaum
-     *            nicht genug Container vorhanden sind
-     */
-    public void setContainer(int i, Container cont) {
-      if ( i>= getContainerCount() )
-        throw new ArrayIndexOutOfBoundsException("not enough Containers in SplitPaneTree");
-
-      int leftCount = 0;
-      if ( isSplittedLeft() ) leftCount = getLeftTree().getContainerCount();
-
-      int rightCount = 0;
-      if ( isSplittedRight() ) rightCount = getRightTree().getContainerCount();
-
-      // erster Container gesucht und kein linker Teilbaum
-      // --> also Container im linken Teil-Pane ist der gesuchte
-      if ( i == 0 && leftCount == 0 )
-        splitPane.setLeftComponent(cont);
-      else
-        // letzter Container gesucht und kein rechter Teilbaum
-        // --> also Container im rechten Teil-Pane ist der gesuchte
-        if ( i == getContainerCount()-1 && rightCount == 0 )
-          splitPane.setRightComponent(cont);
-        else
-          // gesuchter Container liegt im linken Teil-Pane
-          if ( i < leftCount )
-            getLeftTree().setContainer(i,cont);
-          else
-            // gesuchter Container liegt im rechten Teil-Pane
-            getRightTree().setContainer(i-leftCount,cont);
-    }
-
-    /**
-     * Liefert das <code>JSplitPane</code> in dessen linker oder rechter
-     * (bzw. oberer oder unterer) Komponente der i-te Container gespeichert
-     * ist (Zaehlung beginnt bei 0!!).
-     * @exception java.lang.ArrayIndexOutOfBoundsException falls in dem
-     *            (Teil-)Baum weniger als i+1 Container gespeichert sind
-     */
-    public SplitPaneTree getSplitPaneTree(int i) {
-      if ( i>=getContainerCount() )
-        throw new ArrayIndexOutOfBoundsException("not enough Containers in SplitPaneTree");
-
-      int leftCount = 0;
-      if ( isSplittedLeft() ) leftCount = getLeftTree().getContainerCount();
-
-      int rightCount = 0;
-      if ( isSplittedRight() ) rightCount = getRightTree().getContainerCount();
-
-      // erster Container gesucht und kein linker Teilbaum ODER
-      // letzter Container gesucht und kein rechter Teilbaum
-      // --> gesuchter Container liegt im aktuellen SplitPane
-      if ( i == 0                     && leftCount == 0 ||
-           i == getContainerCount()-1 && rightCount == 0)
-        return this;
-
-      // gesuchter Container liegt im linken Teil-Pane
-      if ( i < leftCount )  return getLeftTree().getSplitPaneTree(i);
-
-      // gesuchter Container liegt im rechten Teil-Pane
-      return getRightTree().getSplitPaneTree(i-leftCount);
-    }
-
-    /**
-     * Aendert rekursiv alle SplitPanes (in einem Post-Order-Durchlauf).
-     * Was an den SplitPanes geaendert wird, bestimmt der <code>SplitPaneTreePerformer</code>.
-     * @param performer bestimmt die Verarbeitung der SplitPanes
-     */
-    public void performAllSplitPanes(SplitPaneTreePerformer performer) {
-      if ( isSplittedLeft() )
-        getLeftTree().performAllSplitPanes( performer );
-      if ( isSplittedRight() )
-        getRightTree().performAllSplitPanes( performer );
-      // Orientierung des SplitPanes setzen
-      performer.performSplitPaneTree(this);
-    }
-
-  }
-}
-
-
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Container;
+
+import javax.swing.JComponent;
+import javax.swing.JSplitPane;
+import javax.swing.border.Border;
+
+/**
+ * <hr>
+ * <small><i>Diese Klasse wurde urspruenglich 2002/2003 von <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *            fuer die ADAGIOS-Java-Library (Universitaet Bonn) erstellt, 2009 in das
+ *            SCHMITZM-Projekt uebernommen und teilweise erweitert.</i></small>
+ * <hr>
+ * Ein <code>MultiSplitPane</code> ist eine Menge von horizontal oder
+ * vertikal angeordneten Containern.<br>
+ * Die Groesse dieser <code>Container</code> kann durch den Benutzer manuell
+ * veraendert werden, in dem er die Trennlinien ("Dividers") zwischen den
+ * Containern verschiebt.<br>
+ * Das <code>MultiSplitPane</code> ist implementiert als eine baumartige
+ * Verschachtelung von <code>JSplitPane</code>-Objekten, in denen immer
+ * genau zwei Komponenten hinterlegt werden koennen.<br>
+ * Aus diesem Grund kann die Darstellung der Randbereiche recht
+ * unregelmaessig erscheinen. Deshalb ist es sinnvoll, den Rand entweder
+ * komplett auszuschalten (<code>setInnerBorder(null)</code>), oder einen
+ * unsichtbaren Rand zu verwenden (<code>setInnerBorder( new EmptyBorder(..) )</code>.
+ * Dies gilt vor allem, wenn man ein <code>MultiSplitPane</code> mit vielen
+ * Containern verwendet (mehr als 6 oder 7).
+ * @see javax.swing.JSplitPane
+ * @see javax.swing.JComponent
+ * @see #setInnerBorder(Border)
+ * @see javax.swing.border.EmptyBorder
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ */
+public class MultiSplitPane extends JComponent {
+
+  public static final int HORIZONTAL_SPLIT = JSplitPane.HORIZONTAL_SPLIT;
+  public static final int VERTICAL_SPLIT   = JSplitPane.VERTICAL_SPLIT;
+
+  private Container[]    container     = null;
+  private SplitPaneTree  rootSplitPane = null;
+  private int            orientation   = HORIZONTAL_SPLIT;
+  private int            dividerSize   = 0;
+  private Border         innerBorder   = new JSplitPane().getBorder();
+
+  /**
+   * Erzeugt ein neues MultiSplitPane. Dieses muss aus mindestens
+   * 2 Containern bestehen. Diese werden horizontal angeordnet.
+   * @param compCount   Anzahl an Containern im MultiSplitPane
+   * @exception java.lang.IllegalArgumentException falls die
+   *            Container-Anzahl < 2 ist.
+   */
+  public MultiSplitPane(int compCount) {
+    this(compCount,HORIZONTAL_SPLIT);
+  }
+
+  /**
+   * Erzeugt ein neues MultiSplitPane. Dieses muss aus mindestens
+   * 2 Containern bestehen. Moegliche Orientierungen:
+   * <ul>
+   * <li><code>HORIZONTAL_SPLIT</code></li>
+   * <li><code>VERTICAL_SPLIT</code></li>
+   * </ul>
+   * @param compCount   Anzahl an Containern im MultiSplitPane
+   * @param orientation Orientierung des MultiSplitPane
+   * @exception java.lang.IllegalArgumentException falls die Orientierung
+   *            ungueltig ist oder die Container-Anzahl < 2 ist.
+   */
+  public MultiSplitPane(int compCount, int orientation) {
+    super();
+    this.setLayout( new BorderLayout() );
+
+    if (compCount < 2)
+      throw new IllegalArgumentException("MultiSplitPane must have at least 2 Components");
+    // erstmal nur die Orientierung checken, setzen folgt nachdem
+    // der SplitPaneTree aufgebaut ist
+    checkOrientation(orientation);
+
+    // Referenz auf die Container (der Effizienz wegen) nochmal
+    // in einer Liste speichern
+    container = new Container[compCount];
+    for (int i=0; i<container.length; i++) {
+      container[i] = new Container();
+      container[i].setLayout( new BorderLayout() );
+    }
+    rootSplitPane = new SplitPaneTree(container);
+    // Orientierung setzen
+    setOrientation(orientation);
+    // Basis-SplitPane im Haupt-Container einfuegen
+    this.add(rootSplitPane.getSplitPane());
+  }
+
+  /**
+   * Liefert die Anzahl an Komponenten, in die das SplitPane aufgeteilt ist.
+   */
+  public int getContainerCount() {
+    return container.length;
+  }
+
+  /**
+   * Liefert den Inhalt eine Teil-Panes.
+   * @param i    Index des Teil-Panes (von links/oben nach rechts/unten)
+   * @exception java.lang.ArrayIndexOutOfBoundsException falls ein ungueltiger
+   *            Index angegeben wird
+   */
+  public Container getContainer(int i) {
+    return container[i];
+  }
+
+  /**
+   * Setzt den Inhalt eine Teil-Panes.
+   * @param i    Index des Teil-Panes (von links/oben nach rechts/unten)
+   * @param cont neuer Inhalt des Teil-Panes
+   * @exception java.lang.ArrayIndexOutOfBoundsException falls ein ungueltiger
+   *            Index angegeben wird
+   */
+  public void setContainer(int i, Container cont) {
+    this.container[i] = cont;
+    rootSplitPane.setContainer(i,cont);
+  }
+
+  /**
+   * Liefert die Orientierung in der die Container des MultiSplitPanes
+   * angeordnet sind.
+   * @see #setOrientation(int)
+   */
+  public int getOrientation() {
+    return this.orientation;
+  }
+
+  /**
+   * Aendert die Orientierung des SplitPanes. Moegliche
+   * Orientierungen:
+   * <ul>
+   * <li><code>HORIZONTAL_SPLIT</code></li>
+   * <li><code>VERTICAL_SPLIT</code></li>
+   * </ul>
+   * @param orientation neue Orientierung
+   * @exception java.lang.IllegalArgumentException falls die Orientierung
+   *            ungueltig ist
+   * @see #getOrientation()
+   */
+  public void setOrientation(int orientation) {
+    checkOrientation(orientation);
+
+    final int o = orientation;
+    rootSplitPane.performAllSplitPanes(
+        new SplitPaneTreePerformer() {
+            public void performSplitPaneTree(SplitPaneTree tree) {
+              tree.getSplitPane().setOrientation(o);
+            }
+        }
+    );
+    this.orientation = orientation;
+  }
+
+  /**
+   * Checkt, ob die angegebene Orientierung gueltig ist. Andernfalls wird
+   * eine Exception geworfen.
+   * @param orientation Orientierung
+   * @exception java.lang.IllegalArgumentException falls die Orientierung
+   *            ungueltig ist
+   */
+  protected void checkOrientation(int orientation) {
+    if (orientation != HORIZONTAL_SPLIT &&
+        orientation != VERTICAL_SPLIT)
+      throw new IllegalArgumentException("HORIZONTAL_SPLIT or VERTICAL_SPLIT expected!!");
+  }
+
+  /**
+   * Liefert die Groesse des Dividers (in Pixeln).
+   */
+  public int getDividerSize() {
+    return dividerSize;
+  }
+
+  /**
+   * Setzt die Groesse der Divider-Balken. Die Darstellung des "laestigen"
+   * einpixligen Strichs laesst sich zwar verhindern, indem man die
+   * Divider-Groesse auf 0 setzt, leider sind dann aber auch die Groessen der
+   * einzelnen Container nicht mehr veraenderbar!!
+   * @param size Groesse in Pixeln
+   * @see #getDividerSize()
+   */
+  public void setDividerSize(int size) {
+    final int s = size;
+    rootSplitPane.performAllSplitPanes(
+        new SplitPaneTreePerformer() {
+            public void performSplitPaneTree(SplitPaneTree tree) {
+              tree.getSplitPane().setDividerSize(s);
+            }
+        }
+    );
+    this.dividerSize = size;
+  }
+
+  /**
+   * Liefert das gesetzte Gewicht eines Containers, mit dessen Anteil
+   * dieser bei einer Platzvergroesserung beruecksichtigt wird.
+   * @param i Index des Teil-Panes (von links/oben nach rechts/unten)
+   * @exception java.lang.ArrayIndexOutOfBoundsException falls ein ungueltiger
+   *            Index angegeben wird
+   * @see #setResizeWeigth(double[])
+   */
+  public double getResizeWeight(int i) {
+    // Teilbaum (JSplitPane) suchen, in dem der Container mit
+    // dem Index i abgelegt ist
+    SplitPaneTree tree = rootSplitPane.getSplitPaneTree(i);
+
+    // ResizeWeight-Anteil des SplitPanes
+    double splitPaneWeight = tree.getResizeWeight();
+    // Gewicht der linken Komponente (bezogen auf das eine SplitPane)
+    double weight = tree.getSplitPane().getResizeWeight();
+    // liegt der gesuchte Container im rechten Teil-Pane,
+    // muss das Gegengewicht genommen werden
+    if ( tree.getSplitPane().getLeftComponent() != getContainer(i) )
+      weight = 1 - weight;
+
+    return weight * splitPaneWeight;
+  }
+
+  /**
+   * Liefert die Gewichte aller Containers, mit deren Anteil diese bei
+   * einer Platzvergroesserung beruecksichtigt werden.
+   * @see #getResizeWeight(int)
+   * @see #setResizeWeigth(double[])
+   */
+  public double[] getResizeWeight() {
+    double[] weight = new double[ getContainerCount() ];
+    for (int i=0; i<weight.length; i++)
+      weight[i] = getResizeWeight(i);
+    return weight;
+  }
+
+  /**
+   * Setzt die Container-Gewichtungen, mit deren Anteil diese bei einer
+   * Platzvergroesserung beruecksichtigt werden. Bei der Angabe der
+   * Gewichte sind folgende Punkte zu beachten:
+   * <ul>
+   * <li>Die Summe der angegebenen Gewichte darf 1 nicht ueberschreiten.</li>
+   * <li>Es duerfen hoechstens so viele Gewichte angegeben werden, wie
+   *     Container im <code>MultiSplitPane</code> vorhanden sind.</li>
+   * <li>Werden genau so viele Gewichte angegeben, wie Container im
+   *     <code>MultiSplitPane</code> vorhanden sind, muss die Summe der
+   *     Gewichte 1 ergeben</li>
+   * <li>Werden weniger Gewichte als vorhandene Container angegeben, so wird
+   *     das restliche Gewicht gleichmaessig auf die uebrigen Container
+   *     verteilt.</li>
+   * </ul>
+   * @param weight neue Gewichte
+   * @exception java.lang.IllegalArgumentException falls eine der obigen
+   *            Bedingungen verletzt ist.
+   */
+  public void setResizeWeigth(double[] weight) {
+    if ( weight.length > getContainerCount() )
+      throw new IllegalArgumentException("Es duerfen hoechstens so viele Gewichte, wie Container angegeben werden!");
+
+    // Gewichte in einen Array kopieren, dessen Groesse genau der
+    // Anzahl an Containern entspricht
+    final double[] newWeight = new double[ getContainerCount() ];
+          double   weightSum = 0.0;
+
+    for (int i=0; i<newWeight.length; i++) {
+      if ( i<weight.length ) {
+        weightSum += weight[i]; // Gewichtssumme ermitteln
+        if ( weightSum > 1.0 )
+          throw new IllegalArgumentException("Die angegebnene Summe der Gewichte ist groesser als 1!!");
+        newWeight[i] = weight[i]; // vorhandenes Gewicht kopieren
+      }
+      else {
+        // Bei Angabe von zu wenig Gewichten, wird der Rest "gerecht"
+        // verteilt
+        newWeight[i] = (1-weightSum) / (newWeight.length - weight.length);
+      }
+    }
+
+    if ( weight.length == newWeight.length && weightSum < 1 )
+      throw new IllegalArgumentException("Werden Gewichte fuer alle Container angegeben, muss deren Summe 1 ergeben!!");
+
+    rootSplitPane.performAllSplitPanes(
+        new SplitPaneTreePerformer() {
+            private int contCounter = 0;
+
+            public void performSplitPaneTree(SplitPaneTree tree) {
+              // Beinhaltet das SplitPane einen (finalen) Container
+              // wird dessen neues Gewicht genommen, ansonsten das
+              // Gewicht des gesamten Teilbaums (dieses ist aufgrund
+              // des POSTORDER-Druchlaufs bereits neu berechnet!!)
+              double lWeight = ( !tree.isSplittedLeft() )  ? newWeight[contCounter++] : tree.getLeftResizeWeight();
+              double rWeight = ( !tree.isSplittedRight() ) ? newWeight[contCounter++] : tree.getRightResizeWeight();
+              // neues Gewicht fuer den Teilbaum neu setzen
+              tree.setResizeWeight( lWeight + rWeight );
+              // neues Gewicht fuer das Root-SplitPane des Teilbaum neu setzen
+              tree.getSplitPane().setResizeWeight( lWeight / tree.getResizeWeight() );
+            }
+        });
+  }
+
+  /**
+   * Liefert die Border des <code>MultiSplitPane</code>
+   */
+  public Border getInnerBorder() {
+    return this.innerBorder;
+  }
+
+  /**
+   * Setzt die Border fuer alle Container.
+   */
+  public void setInnerBorder(final Border border) {
+    rootSplitPane.performAllSplitPanes(
+        new SplitPaneTreePerformer() {
+            public void performSplitPaneTree(SplitPaneTree tree) {
+              tree.getSplitPane().setBorder(border);
+            }
+        });
+    this.innerBorder = border;
+  }
+
+  /////////////////////////////////////////////////////////////////////////
+  ///// Interface   SplitPaneTreePerformer                            /////
+  /////////////////////////////////////////////////////////////////////////
+  private interface SplitPaneTreePerformer {
+    public void performSplitPaneTree(SplitPaneTree tree);
+  }
+
+  /////////////////////////////////////////////////////////////////////////
+  ///// Klasse   SplitPaneTree                                        /////
+  /////////////////////////////////////////////////////////////////////////
+  private class SplitPaneTree {
+    private JSplitPane    splitPane    = null;
+    private int           contCount    = 0;
+    private SplitPaneTree leftTree     = null;
+    private SplitPaneTree rightTree    = null;
+    private double        resizeWeight = 0.0;
+
+    /**
+     * Interner Konstruktor zum Initialisieren ALLER Variablen.
+     */
+    private void init(JSplitPane splitPane, int contCount, double weight, SplitPaneTree left, SplitPaneTree right) {
+      this.splitPane    = splitPane;
+      this.contCount    = contCount;
+      this.resizeWeight = weight;
+      this.leftTree     = left;
+      this.rightTree    = right;
+    }
+
+    /**
+     * Interner Konstruktor zum Initialisieren eines (Teil-)Baums, der
+     * sowohl links, als auch rechts weiter geplittet ist.
+     */
+    private void initInner(JSplitPane splitPane, double weight, SplitPaneTree left, SplitPaneTree right) {
+      init(splitPane,left.getContainerCount()+right.getContainerCount(),weight,left,right);
+    }
+
+    /**
+     * Erzeugt einen neuen (Teil-)Baum, der sowohl links, als auch rechts
+     * weiter gesplittet ist. Beide Teil-Panes sind also weiter unterteilt.
+     * @param splitPane <code>JSplitPane</code> fuer das der (Teil-)Baum steht
+     * @param weight    Gewicht des Teilbaums bezogen auf den gesamten Baum
+     *                  (Anteil am neuen Platz, den die Container im Teilbaum
+     *                  erhalten, wenn sich das Pane vergroessert)
+     * @param left      linker Teilbaum
+     * @param right     rechter Teilbaum
+     */
+    public SplitPaneTree(JSplitPane splitPane, double weight, SplitPaneTree left, SplitPaneTree right) {
+      initInner(splitPane,weight,left,right);
+    }
+
+    /**
+     * Interner Konstruktor zum Initialisieren eines Blattes.
+     */
+    private void initLeaf(JSplitPane splitPane, double weight) {
+      init(splitPane,2,weight,null,null);
+    }
+
+    /**
+     * Erzeugt ein neues Blatt. Beide Teil-Panes enthalten also einen
+     * <code>Container</code> und sind nicht weiter gesplittet.
+     * @param splitPane <code>JSplitPane</code> fuer das der (Teil-)Baum steht
+     * @param weight    Gewicht des Teilbaums bezogen auf den gesamten Baum
+     *                  (Anteil am neuen Platz, den die Container im Teilbaum
+     *                  erhalten, wenn sich das Pane vergroessert)
+     */
+    public SplitPaneTree(JSplitPane splitPane, double weight) {
+      initLeaf(splitPane,weight);
+    }
+
+    /**
+     * Interner Konstruktor zum Initialisieren eines (Teil-)Baums, der
+     * links gesplittet ist und rechts ein Blatt hat.
+     */
+    private void initHalfLeaf(JSplitPane splitPane, double weight, SplitPaneTree left) {
+      init(splitPane,left.getContainerCount()+1,weight,left,null);
+    }
+
+    /**
+     * Erzeugt einen neuen (Teil-)Baum, der nach links gesplittet ist und rechts
+     * endet ("Halb-Blatt"). Das linke Teil-Pane ist also weiter unterteilt, waehrend im
+     * rechten Teil-Pane ein <code>Container</code> zu finden ist.
+     * @param splitPane <code>JSplitPane</code> fuer das der (Teil-)Baum steht
+     * @param weight    Gewicht des Teilbaums bezogen auf den gesamten Baum
+     *                  (Anteil am neuen Platz, den die Container im Teilbaum
+     *                  erhalten, wenn sich das Pane vergroessert)
+     * @param left      linker Teilbaum
+     */
+    public SplitPaneTree(JSplitPane splitPane, double weight, SplitPaneTree left) {
+      initHalfLeaf(splitPane,weight,left);
+    }
+
+    /**
+     * Erzeugt einen neuen Baum.
+     * @param container Container, die das SplitPane haben soll
+     * @param start     Index im <code>Container</code>-Array, bei dem
+     *                  begonnen wird (alle davor werden ignoriert)
+     * @param weight    Gewicht des Teilbaums bezogen auf den gesamten Baum
+     *                  (Anteil am neuen Platz, den die Container im Teilbaum
+     *                  erhalten, wenn sich das Pane vergroessert)
+     */
+    public SplitPaneTree(Container[] container, int start, int count, double weight) {
+//  System.out.println(start+"\t"+count+"\t"+weight);
+      if ( count < 2 )
+        throw new IllegalArgumentException("SplitPane must have at least 2 Containers");
+
+      if ( start + count -1 >= container.length )
+        throw new IllegalArgumentException("'count' too big for this start position in Container-Array");
+
+      this.splitPane = new JSplitPane();
+
+      // Aufteilung ermitteln
+      int rightCount  = count / 2;
+      int leftCount   = count - rightCount;
+      // Vergroesserungs-Gewichte ermitteln:
+      // --> Entsprechend der Aufteilung erhalten die beiden Teil-Panes
+      //     einen Anteil am Gesamt-Gewicht des SplitPanes
+      double rightWeight = weight/count * rightCount;
+      double leftWeight  = weight/count * leftCount;
+
+      // bei nur 2 Teil-Panes wird nicht mehr weiter gesplitten
+      // --> Blatt erzeugen
+      if ( leftCount == 1 && rightCount == 1 )
+        initLeaf(splitPane,weight);
+
+      // nur das linke Teil-Pane wird weitergesplittet
+      // --> Halb-Blatt erzeugen
+      if ( leftCount > 1 && rightCount == 1)
+        initHalfLeaf(splitPane,weight,new SplitPaneTree(container,start,leftCount,leftWeight));
+
+      // beider Teil-Panes werden weitergesplittet
+      // --> Inneren Knoten erzeugen
+      if ( leftCount > 1 && rightCount > 1)
+        initInner(splitPane,weight, new SplitPaneTree(container,start,leftCount,leftWeight),
+                                    new SplitPaneTree(container,start+leftCount,rightCount,rightWeight) );
+
+      // Das Split-Pane initialisieren, fuer das dieser Knoten steht
+//  System.out.println(start+"\t"+count+"\t"+isSplittedLeft()+"\t"+isSplittedRight());
+      if ( this.isSplittedLeft() )
+        this.splitPane.setLeftComponent( this.getLeftTree().getSplitPane() );
+      else
+        this.splitPane.setLeftComponent( container[ start ] );
+
+      if ( this.isSplittedRight() )
+        this.splitPane.setRightComponent( this.getRightTree().getSplitPane() );
+      else
+        this.splitPane.setRightComponent( container[ start+count-1 ] );
+
+      this.splitPane.setResizeWeight(leftWeight/weight);
+    }
+
+    /**
+     * Erzeugt einen neuen Baum.
+     * @param container Container, die das SplitPane haben soll
+     * @param start     Index im <code>Container</code>-Array, bei dem
+     *                  begonnen wird (alle davor werden ignoriert)
+     * @param weight    Gewicht des Teilbaums bezogen auf den gesamten Baum
+     *                  (Anteil am neuen Platz, den die Container im Teilbaum
+     *                  erhalten, wenn sich das Pane vergroessert)
+     */
+    public SplitPaneTree(Container[] container, int start, double weight) {
+      this(container,start,container.length - start,weight);
+    }
+
+    /**
+     * Erzeugt einen neuen Baum.
+     * @param container Container, die das SplitPane haben soll
+     */
+    public SplitPaneTree(Container[] container) {
+      this(container,0,1.0);
+    }
+
+    /**
+     * Liefert das <code>JSplitPane</code> fuer das der Knoten steht.
+     */
+    public JSplitPane getSplitPane() {
+      return splitPane;
+    }
+
+    /**
+     * Liefert die Anzahl an Containern, die im Teil-Baum vorhanden sind.
+     */
+    public int getContainerCount() {
+      return contCount;
+    }
+
+    /**
+     * Checkt, ob das linke (obere) Teil-Pane wiederum gesplittet ist
+     * (<code>true</code>) oder einen Container enthaelt (<code>false</code>).
+     */
+    public boolean isSplittedLeft() {
+      return getLeftTree() != null;
+    }
+
+    /**
+     * Liefert den linken Teilbaum des aktuellen Knoten.
+     * @return <code>null</code>, falls das linke (obere) Teil-Pane einen
+     *         Container enthaelt und nicht weiter gesplittet ist.
+     */
+    public SplitPaneTree getLeftTree() {
+      return leftTree;
+    }
+
+    /**
+     * Checkt, ob das rechte (untere) Teil-Pane wiederum gesplittet ist
+     * (<code>true</code>) oder einen Container enthaelt (<code>false</code>).
+     */
+    public boolean isSplittedRight() {
+      return getRightTree() != null;
+    }
+
+    /**
+     * Liefert den rechten Teilbaum des aktuellen Knoten.
+     * @return <code>null</code>, falls das rechte (untere) Teil-Pane einen
+     *         Container enthaelt und nicht weiter gesplittet ist.
+     */
+    public SplitPaneTree getRightTree() {
+      return rightTree;
+    }
+
+    /**
+     * Aendert den Gesamt-Anteil am neuen Platz, den die Container im (Teil-Baum)
+     * erhalten.<br>
+     * <b>Diese Methode sollte nur in einem kontrollierten Durchlauf durch
+     * alle Teilbaeume verwendet werden, in dem gewaehrleistet ist, dass
+     * mit der Aenderung des Gewichts auch die Gewichte der anderen Teilbaeume
+     * korrekt abgeaendert werden!! Die macht diese Methode naemlich
+     * <u>nicht</u> automatisch!!</b>
+     */
+    public void setResizeWeight(double weight) {
+      this.resizeWeight = weight;
+    }
+
+    /**
+     * Liefert den Anteil am gesamten neuen Platz, den die Container erhalten,
+     * die im (Teil-)Baums liegen.
+     */
+    public double getResizeWeight() {
+      return resizeWeight;
+    }
+
+    /**
+     * Liefert den Anteil am gesamten neuen Platz, den die Container erhalten,
+     * die im linken Teil-Baum (also im linken/oberen Teil-Pane) liegen.
+     */
+    public double getLeftResizeWeight() {
+      if ( isSplittedLeft() ) return getLeftTree().getResizeWeight();
+      return getSplitPane().getResizeWeight() * getResizeWeight();
+    }
+
+    /**
+     * Liefert den Anteil am gesamten neuen Platz, den die Container erhalten,
+     * die im rechten Teil-Baum (also im rechten/unteren Teil-Pane) liegen.
+     */
+    public double getRightResizeWeight() {
+      if ( isSplittedRight() ) return getRightTree().getResizeWeight();
+      return (1-getSplitPane().getResizeWeight()) * getResizeWeight();
+    }
+
+    /**
+     * Liefert den Container eines Blattes aus dem (Teil-)Baum. Dabei sind die
+     * Container (mit 0 beginnend) von links nach recht im Baum durchnummeriert.
+     * @param i Nummer des Containers
+     * @exception lava.lang.ArrayIndexOutOfBoundsException falls in dem Teilbaum
+     *            nicht genug Container vorhanden sind
+     */
+    public Container getContainer(int i) {
+      if ( i>= getContainerCount() )
+        throw new ArrayIndexOutOfBoundsException("not enough Containers in SplitPaneTree");
+
+      int leftCount = 0;
+      if ( isSplittedLeft() ) leftCount = getLeftTree().getContainerCount();
+
+      int rightCount = 0;
+      if ( isSplittedRight() ) rightCount = getRightTree().getContainerCount();
+
+      // erster Container gesucht und kein linker Teilbaum
+      // --> also Container im linken Teil-Pane ist der gesuchte
+      if ( i == 0 && leftCount == 0 )
+        return (Container)splitPane.getLeftComponent();
+      // letzter Container gesucht und kein rechter Teilbaum
+      // --> also Container im rechten Teil-Pane ist der gesuchte
+      if ( i == getContainerCount()-1 && rightCount == 0 )
+        return (Container)splitPane.getRightComponent();
+      // gesuchter Container liegt im linken Teil-Pane
+      if ( i < leftCount )
+        return getLeftTree().getContainer(i);
+      // gesuchter Container liegt im rechten Teil-Pane
+      return getRightTree().getContainer(i-leftCount);
+    }
+
+    /**
+     * Liefert den Container eines Blattes aus dem (Teil-)Baum. Dabei sind die
+     * Container (mit 0 beginnend) von links nach recht im Baum durchnummeriert.
+     * @param i Nummer des Containers
+     * @exception lava.lang.ArrayIndexOutOfBoundsException falls in dem Teilbaum
+     *            nicht genug Container vorhanden sind
+     */
+    public void setContainer(int i, Container cont) {
+      if ( i>= getContainerCount() )
+        throw new ArrayIndexOutOfBoundsException("not enough Containers in SplitPaneTree");
+
+      int leftCount = 0;
+      if ( isSplittedLeft() ) leftCount = getLeftTree().getContainerCount();
+
+      int rightCount = 0;
+      if ( isSplittedRight() ) rightCount = getRightTree().getContainerCount();
+
+      // erster Container gesucht und kein linker Teilbaum
+      // --> also Container im linken Teil-Pane ist der gesuchte
+      if ( i == 0 && leftCount == 0 )
+        splitPane.setLeftComponent(cont);
+      else
+        // letzter Container gesucht und kein rechter Teilbaum
+        // --> also Container im rechten Teil-Pane ist der gesuchte
+        if ( i == getContainerCount()-1 && rightCount == 0 )
+          splitPane.setRightComponent(cont);
+        else
+          // gesuchter Container liegt im linken Teil-Pane
+          if ( i < leftCount )
+            getLeftTree().setContainer(i,cont);
+          else
+            // gesuchter Container liegt im rechten Teil-Pane
+            getRightTree().setContainer(i-leftCount,cont);
+    }
+
+    /**
+     * Liefert das <code>JSplitPane</code> in dessen linker oder rechter
+     * (bzw. oberer oder unterer) Komponente der i-te Container gespeichert
+     * ist (Zaehlung beginnt bei 0!!).
+     * @exception java.lang.ArrayIndexOutOfBoundsException falls in dem
+     *            (Teil-)Baum weniger als i+1 Container gespeichert sind
+     */
+    public SplitPaneTree getSplitPaneTree(int i) {
+      if ( i>=getContainerCount() )
+        throw new ArrayIndexOutOfBoundsException("not enough Containers in SplitPaneTree");
+
+      int leftCount = 0;
+      if ( isSplittedLeft() ) leftCount = getLeftTree().getContainerCount();
+
+      int rightCount = 0;
+      if ( isSplittedRight() ) rightCount = getRightTree().getContainerCount();
+
+      // erster Container gesucht und kein linker Teilbaum ODER
+      // letzter Container gesucht und kein rechter Teilbaum
+      // --> gesuchter Container liegt im aktuellen SplitPane
+      if ( i == 0                     && leftCount == 0 ||
+           i == getContainerCount()-1 && rightCount == 0)
+        return this;
+
+      // gesuchter Container liegt im linken Teil-Pane
+      if ( i < leftCount )  return getLeftTree().getSplitPaneTree(i);
+
+      // gesuchter Container liegt im rechten Teil-Pane
+      return getRightTree().getSplitPaneTree(i-leftCount);
+    }
+
+    /**
+     * Aendert rekursiv alle SplitPanes (in einem Post-Order-Durchlauf).
+     * Was an den SplitPanes geaendert wird, bestimmt der <code>SplitPaneTreePerformer</code>.
+     * @param performer bestimmt die Verarbeitung der SplitPanes
+     */
+    public void performAllSplitPanes(SplitPaneTreePerformer performer) {
+      if ( isSplittedLeft() )
+        getLeftTree().performAllSplitPanes( performer );
+      if ( isSplittedRight() )
+        getRightTree().performAllSplitPanes( performer );
+      // Orientierung des SplitPanes setzen
+      performer.performSplitPaneTree(this);
+    }
+
+  }
+}
+
+

Modified: trunk/src/schmitzm/swing/MultipleOptionPane.java
===================================================================
--- trunk/src/schmitzm/swing/MultipleOptionPane.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/MultipleOptionPane.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,176 +1,194 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing;
-
-import java.awt.Component;
-
-import javax.swing.JDialog;
-import javax.swing.JOptionPane;
-
-/**
- * Diese Klasse erweitert {@link JOptionPane} um einen Ok/Abbrechen-Dialog, der
- * mehrfache Werte gleichzeitig abfragt. Die Art der Eingaben wird ueber
- * Instanzen der  Klasse {@link InputOption} spezifiziert.<br>
- * Ueber die statische Funktion
- * {@link #showMultipleInputDialog(Component,String,InputOption[])} kann ein
- * solcher Dialog angezeigt werden.<br>
- * Darueber hinaus bietet die statische Funktion
- * {@link #showClassAndDescInputDialog(Component,String,Class[],String)} einen
- * speziellen Dialog, der eine Auswahl an Klassennamen anzeigt und zu der
- * ausgewaehlten Klasse eine Beschreibung abfragt.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class MultipleOptionPane extends JOptionPane {
-  /** Speichert die Eingabe-Optionen des MultipleOptionPane. */
-  protected InputOption[] multipleOption = null;
-
-  /**
-   * Erzeugt einen neuen Ok/Abbrechen-Dialog mit mehrfachen Eingabefeldern.
-   * @param multipleOption Eingabe-Optionen
-   */
-  public MultipleOptionPane(InputOption[] multipleOption) {
-    super();
-    this.multipleOption = multipleOption.clone();
-    this.setMessageType(JOptionPane.INFORMATION_MESSAGE);
-    this.setOptionType(JOptionPane.OK_CANCEL_OPTION);
-    this.setMessage( this.multipleOption );
-  }
-
-  /**
-   * Liefert die Eingabe-Optionen des <code>MultipleOptionPane</code>.
-   */
-  public InputOption[] getMultipleOptions() {
-    return multipleOption.clone();
-  }
-
-  /**
-   * Prueft, ob die Eingaben in allen Felden zulaessig sind.
-   */
-  public boolean multipleOptionsValid() {
-    return getInvalidOption() == null;
-  }
-
-  /**
-   * Prueft, ob alle Eingaben zulaessig sind und gibt die erste fehlerhafte
-   * Option zurueck.
-   * @return <code>null</code> wenn alle Eingaben korrekt sind
-   */
-  private InputOption getInvalidOption() {
-    for (int i=0; i<multipleOption.length; i++)
-      if ( !multipleOption[i].isInputValid() )
-        return multipleOption[i];
-    return null;
-  }
-
-  /**
-   * Liefert die Eingaben, die in dem <code>MultipleOptionPane</code>
-   * gemacht wurden.
-   * @return <code>null</code> falls der Dialog noch aktiv ist oder
-   *         nicht ueber die Ok-Option verlassen wurde
-   */
-  public Object[] getMultipleOptionValues() {
-    if ( getValue() == null || (Integer)getValue() != JOptionPane.OK_OPTION)
-      return null;
-    Object[] value = new Object[ multipleOption.length ];
-    for (int i=0; i<value.length; i++)
-      value[i] = multipleOption[i].getValue();
-    return value;
-  }
-
-  /**
-   * Zeigt einen modalen Ok/Abbrechen-Dialog mit mehrfachen Eingabefeldern an.
-   * @param parent Uebergeordnetes Fenster, in dem der Dialog angezeigt wird
-   *               (kann <code>null</code> sein)
-   * @param title  Titel fuer den Dialog
-   * @param option Eingabefelder
-   * @return die Werte, die in den einzelnen Feldern gemacht wurden, oder
-   *         <code>null</code>, falls der Dialog nicht ueber die Ok-Option
-   *         verlassen wurde
-   */
-  public static Object[] showMultipleInputDialog(Component parent, String title, InputOption... option) {
-    MultipleOptionPane pane   = new MultipleOptionPane(option);
-    JDialog            dialog = pane.createDialog(parent,title);
-    InputOption        invalidOption = null;
-    do {
-      dialog.setVisible(true);
-      boolean cancel = pane.getValue() == null || ((Integer)pane.getValue() != JOptionPane.OK_OPTION);
-      invalidOption = !cancel ? pane.getInvalidOption() : null;
-
-      if ( invalidOption != null ) {
-        String invalidOptionName = invalidOption.getLabel();
-        String errorDesc         = invalidOption.getInvalidInputMessage();
-        String mess = SwingUtil.RESOURCE.getString("InvalidInputMess");
-        if ( invalidOptionName != null && !invalidOptionName.trim().equals("") )
-          mess = mess.concat(": '").concat(invalidOptionName).concat("'");
-        if ( errorDesc != null && !errorDesc.trim().equals("") )
-          mess = mess.concat("\n").concat(errorDesc);
-        showMessageDialog(pane,mess,SwingUtil.RESOURCE.getString("Error"),JOptionPane.ERROR_MESSAGE);
-      }
-
-    } while ( invalidOption != null );
-    return pane.getMultipleOptionValues();
-  }
-
-  /**
-   * Zeigt einen modalen Ok/Abbrechen-Dialog mit einem Klassen-Auswahlfeld und
-   * einem Text-Eingabefeld fuer eine Beschreibung an. Eine Eingabe in beiden
-   * Feldern ist zwingend erforderlich.
-   * @param parent      Uebergeordnetes Fenster, in dem der Dialog angezeigt wird
-   *                    (kann <code>null</code> sein)
-   * @param title       Titel fuer den Dialog
-   * @param classOption Klassen, die im Dialog zur Auswahl gestellt werden
-   * @param defaultText Default-Wert fuer das Text-Eingabefeld
-   * @return Array mit 2 Werten (0 = ausgewaehlte Klasse [<code>Class</code>];
-   *         1 = eingegebene Beschreibung [<code>String</code>]), oder
-   *         <code>null</code>, falls der Dialog nicht ueber die Ok-Option
-   *         verlassen wurde
-   */
-  public static Object[] showClassAndDescInputDialog(Component parent, String title, Class[] classOption, String defaultText) {
-    String[] classDesc = new String[classOption.length];
-    for (int i=0; i<classDesc.length; i++)
-      classDesc[i] = classOption[i].getName();
-
-    return showMultipleInputDialog(
-      parent,
-      title,
-        new InputOption[] { new SelectionInputOption.Combo(SwingUtil.RESOURCE.getString("Class")+":",true,classOption,classDesc),
-                            new ManualInputOption.Text(SwingUtil.RESOURCE.getString("Description")+":",true,defaultText) }
-    );
-  }
-
-
-  /**
-   * Zeigt einen Dialog mit mehreren Options-Buttons dar.
-   * @param parent       Parent-Komponente, ueber der der Dialog angezeigt wird
-   * @param type         Art der Meldung ({@link JOptionPane#ERROR_MESSAGE},
-   *                     {@link JOptionPane#INFORMATION_MESSAGE} oder {@link JOptionPane#QUESTION_MESSAGE})
-   * @param title        Titel des Dialog-Fensters
-   * @param message      Meldung die angezeigt wird
-   * @param options      Bezeichnungen der Button, die zur Auswahl stehen
-   * @param initialValue Bezeichnung des standardmaessig ausgewaehlten Button
-   * @return Die Bezeichnung ({@code String}) des Buttons, der ausgewaehlt wurde,
-   *         oder {@code null}, wenn der Dialog ueber das System-Menu abgebrochen
-   *         wurde
-   */
-  public static Object showMultipleOptionDialog(Component parent, int type, String title, Object message, String[] options, String initialValue) {
-    JOptionPane optionPane = new JOptionPane();
-    optionPane.setMessageType(type);
-    optionPane.setOptionType(JOptionPane.OK_CANCEL_OPTION);
-    optionPane.setMessage( message );
-    optionPane.setOptions( options );
-    optionPane.setInitialValue(initialValue);
-    JDialog dialog = optionPane.createDialog(parent,title);
-    dialog.setVisible(true);
-    return optionPane.getValue();
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
+
+import java.awt.Component;
+
+import javax.swing.JDialog;
+import javax.swing.JOptionPane;
+
+/**
+ * Diese Klasse erweitert {@link JOptionPane} um einen Ok/Abbrechen-Dialog, der
+ * mehrfache Werte gleichzeitig abfragt. Die Art der Eingaben wird ueber
+ * Instanzen der  Klasse {@link InputOption} spezifiziert.<br>
+ * Ueber die statische Funktion
+ * {@link #showMultipleInputDialog(Component,String,InputOption[])} kann ein
+ * solcher Dialog angezeigt werden.<br>
+ * Darueber hinaus bietet die statische Funktion
+ * {@link #showClassAndDescInputDialog(Component,String,Class[],String)} einen
+ * speziellen Dialog, der eine Auswahl an Klassennamen anzeigt und zu der
+ * ausgewaehlten Klasse eine Beschreibung abfragt.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class MultipleOptionPane extends JOptionPane {
+  /** Speichert die Eingabe-Optionen des MultipleOptionPane. */
+  protected InputOption[] multipleOption = null;
+
+  /**
+   * Erzeugt einen neuen Ok/Abbrechen-Dialog mit mehrfachen Eingabefeldern.
+   * @param multipleOption Eingabe-Optionen
+   */
+  public MultipleOptionPane(InputOption[] multipleOption) {
+    super();
+    this.multipleOption = multipleOption.clone();
+    this.setMessageType(JOptionPane.INFORMATION_MESSAGE);
+    this.setOptionType(JOptionPane.OK_CANCEL_OPTION);
+    this.setMessage( this.multipleOption );
+  }
+
+  /**
+   * Liefert die Eingabe-Optionen des <code>MultipleOptionPane</code>.
+   */
+  public InputOption[] getMultipleOptions() {
+    return multipleOption.clone();
+  }
+
+  /**
+   * Prueft, ob die Eingaben in allen Felden zulaessig sind.
+   */
+  public boolean multipleOptionsValid() {
+    return getInvalidOption() == null;
+  }
+
+  /**
+   * Prueft, ob alle Eingaben zulaessig sind und gibt die erste fehlerhafte
+   * Option zurueck.
+   * @return <code>null</code> wenn alle Eingaben korrekt sind
+   */
+  private InputOption getInvalidOption() {
+    for (int i=0; i<multipleOption.length; i++)
+      if ( !multipleOption[i].isInputValid() )
+        return multipleOption[i];
+    return null;
+  }
+
+  /**
+   * Liefert die Eingaben, die in dem <code>MultipleOptionPane</code>
+   * gemacht wurden.
+   * @return <code>null</code> falls der Dialog noch aktiv ist oder
+   *         nicht ueber die Ok-Option verlassen wurde
+   */
+  public Object[] getMultipleOptionValues() {
+    if ( getValue() == null || (Integer)getValue() != JOptionPane.OK_OPTION)
+      return null;
+    Object[] value = new Object[ multipleOption.length ];
+    for (int i=0; i<value.length; i++)
+      value[i] = multipleOption[i].getValue();
+    return value;
+  }
+
+  /**
+   * Zeigt einen modalen Ok/Abbrechen-Dialog mit mehrfachen Eingabefeldern an.
+   * @param parent Uebergeordnetes Fenster, in dem der Dialog angezeigt wird
+   *               (kann <code>null</code> sein)
+   * @param title  Titel fuer den Dialog
+   * @param option Eingabefelder
+   * @return die Werte, die in den einzelnen Feldern gemacht wurden, oder
+   *         <code>null</code>, falls der Dialog nicht ueber die Ok-Option
+   *         verlassen wurde
+   */
+  public static Object[] showMultipleInputDialog(Component parent, String title, InputOption... option) {
+    MultipleOptionPane pane   = new MultipleOptionPane(option);
+    JDialog            dialog = pane.createDialog(parent,title);
+    InputOption        invalidOption = null;
+    do {
+      dialog.setVisible(true);
+      boolean cancel = pane.getValue() == null || ((Integer)pane.getValue() != JOptionPane.OK_OPTION);
+      invalidOption = !cancel ? pane.getInvalidOption() : null;
+
+      if ( invalidOption != null ) {
+        String invalidOptionName = invalidOption.getLabel();
+        String errorDesc         = invalidOption.getInvalidInputMessage();
+        String mess = SwingUtil.RESOURCE.getString("InvalidInputMess");
+        if ( invalidOptionName != null && !invalidOptionName.trim().equals("") )
+          mess = mess.concat(": '").concat(invalidOptionName).concat("'");
+        if ( errorDesc != null && !errorDesc.trim().equals("") )
+          mess = mess.concat("\n").concat(errorDesc);
+        showMessageDialog(pane,mess,SwingUtil.RESOURCE.getString("Error"),JOptionPane.ERROR_MESSAGE);
+      }
+
+    } while ( invalidOption != null );
+    return pane.getMultipleOptionValues();
+  }
+
+  /**
+   * Zeigt einen modalen Ok/Abbrechen-Dialog mit einem Klassen-Auswahlfeld und
+   * einem Text-Eingabefeld fuer eine Beschreibung an. Eine Eingabe in beiden
+   * Feldern ist zwingend erforderlich.
+   * @param parent      Uebergeordnetes Fenster, in dem der Dialog angezeigt wird
+   *                    (kann <code>null</code> sein)
+   * @param title       Titel fuer den Dialog
+   * @param classOption Klassen, die im Dialog zur Auswahl gestellt werden
+   * @param defaultText Default-Wert fuer das Text-Eingabefeld
+   * @return Array mit 2 Werten (0 = ausgewaehlte Klasse [<code>Class</code>];
+   *         1 = eingegebene Beschreibung [<code>String</code>]), oder
+   *         <code>null</code>, falls der Dialog nicht ueber die Ok-Option
+   *         verlassen wurde
+   */
+  public static Object[] showClassAndDescInputDialog(Component parent, String title, Class[] classOption, String defaultText) {
+    String[] classDesc = new String[classOption.length];
+    for (int i=0; i<classDesc.length; i++)
+      classDesc[i] = classOption[i].getName();
+
+    return showMultipleInputDialog(
+      parent,
+      title,
+        new InputOption[] { new SelectionInputOption.Combo(SwingUtil.RESOURCE.getString("Class")+":",true,classOption,classDesc),
+                            new ManualInputOption.Text(SwingUtil.RESOURCE.getString("Description")+":",true,defaultText) }
+    );
+  }
+
+
+  /**
+   * Zeigt einen Dialog mit mehreren Options-Buttons dar.
+   * @param parent       Parent-Komponente, ueber der der Dialog angezeigt wird
+   * @param type         Art der Meldung ({@link JOptionPane#ERROR_MESSAGE},
+   *                     {@link JOptionPane#INFORMATION_MESSAGE} oder {@link JOptionPane#QUESTION_MESSAGE})
+   * @param title        Titel des Dialog-Fensters
+   * @param message      Meldung die angezeigt wird
+   * @param options      Bezeichnungen der Button, die zur Auswahl stehen
+   * @param initialValue Bezeichnung des standardmaessig ausgewaehlten Button
+   * @return Die Bezeichnung ({@code String}) des Buttons, der ausgewaehlt wurde,
+   *         oder {@code null}, wenn der Dialog ueber das System-Menu abgebrochen
+   *         wurde
+   */
+  public static Object showMultipleOptionDialog(Component parent, int type, String title, Object message, String[] options, String initialValue) {
+    JOptionPane optionPane = new JOptionPane();
+    optionPane.setMessageType(type);
+    optionPane.setOptionType(JOptionPane.OK_CANCEL_OPTION);
+    optionPane.setMessage( message );
+    optionPane.setOptions( options );
+    optionPane.setInitialValue(initialValue);
+    JDialog dialog = optionPane.createDialog(parent,title);
+    dialog.setVisible(true);
+    return optionPane.getValue();
+  }
+}

Modified: trunk/src/schmitzm/swing/ObjectDisplayContainer.java
===================================================================
--- trunk/src/schmitzm/swing/ObjectDisplayContainer.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/ObjectDisplayContainer.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,76 +1,94 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+import java.awt.Component;
+import java.awt.Container;
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+/**
+ * Diese Klasse repraesentiert eine abstrakte Oberklasse fuer alle GUI-Komponenten,
+ * die ein (allgemeines) Datenobjekt darstellen.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public abstract class ObjectDisplayContainer extends Container {
+  /** Speichert eine Referent auf den Container (<code>this</code>). */
+  protected final Component GUI_COMPONENT  = this;
+  /** Speichert das dargestellte Objekt. */
+  protected Object data = null;
 
-package schmitzm.swing;
-
-import java.awt.Component;
-import java.awt.Container;
-
-/**
- * Diese Klasse repraesentiert eine abstrakte Oberklasse fuer alle GUI-Komponenten,
- * die ein (allgemeines) Datenobjekt darstellen.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public abstract class ObjectDisplayContainer extends Container {
-  /** Speichert eine Referent auf den Container (<code>this</code>). */
-  protected final Component GUI_COMPONENT  = this;
-  /** Speichert das dargestellte Objekt. */
-  protected Object data = null;
-
-  /**
-   * Erzeugt eine neue Darstellungskomponente.
-   */
-  public ObjectDisplayContainer() {
-    this(null);
-  }
-
-  /**
-   * Erzeugt eine neue Darstellungskomponente und zeigt sofort ein
-   * Objekt an.
-   * @param data anzuzeigendes Objekt
-   */
-  public ObjectDisplayContainer(Object data) {
-    setObject(data);
-  }
-
-  /**
-   * Setzt das darzustellende Objekt. Wird <code>null</code> uebergeben,
-   * wird das bisher dargestellte Objekt entfernt.
-   * @exception UnsupportedOperationException falls das angegebene Objekt
-   *            nicht dargestellt werden kann.
-   * @see #canDisplay(Object)
-   */
-  public void setObject(Object data) {
-    if ( data!=null && !canDisplay(data) )
-      throw new UnsupportedOperationException( getClass().getSimpleName().concat(" can not display an instance of ").concat(data.getClass().getName()) );
-    this.data = data;
-    refresh();
-  }
-
-  /**
-   * Liefert das aktuell dargestellte Objekt.
-   * @return <code>null</code> falls aktuell kein Objekt dargestellt wird
-   */
-  public Object getObject() {
-    return data;
-  }
-
-  /**
-   * Prueft, ob ein Objekt darstellbar ist.
-   */
-  public abstract boolean canDisplay(Object data);
-
-  /**
-   * Aktualisiert die Darstellung des aktuell angezeigten Objekts.
-   */
-  public abstract void refresh();
-}
+  /**
+   * Erzeugt eine neue Darstellungskomponente.
+   */
+  public ObjectDisplayContainer() {
+    this(null);
+  }
+
+  /**
+   * Erzeugt eine neue Darstellungskomponente und zeigt sofort ein
+   * Objekt an.
+   * @param data anzuzeigendes Objekt
+   */
+  public ObjectDisplayContainer(Object data) {
+    setObject(data);
+  }
+
+  /**
+   * Setzt das darzustellende Objekt. Wird <code>null</code> uebergeben,
+   * wird das bisher dargestellte Objekt entfernt.
+   * @exception UnsupportedOperationException falls das angegebene Objekt
+   *            nicht dargestellt werden kann.
+   * @see #canDisplay(Object)
+   */
+  public void setObject(Object data) {
+    if ( data!=null && !canDisplay(data) )
+      throw new UnsupportedOperationException( getClass().getSimpleName().concat(" can not display an instance of ").concat(data.getClass().getName()) );
+    this.data = data;
+    refresh();
+  }
+
+  /**
+   * Liefert das aktuell dargestellte Objekt.
+   * @return <code>null</code> falls aktuell kein Objekt dargestellt wird
+   */
+  public Object getObject() {
+    return data;
+  }
+
+  /**
+   * Prueft, ob ein Objekt darstellbar ist.
+   */
+  public abstract boolean canDisplay(Object data);
+
+  /**
+   * Aktualisiert die Darstellung des aktuell angezeigten Objekts.
+   */
+  public abstract void refresh();
+}

Modified: trunk/src/schmitzm/swing/OperationTreePanel.java
===================================================================
--- trunk/src/schmitzm/swing/OperationTreePanel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/OperationTreePanel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,403 +1,421 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing;
-
-import java.awt.Dimension;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Vector;
-
-import javax.swing.JButton;
-import javax.swing.JComboBox;
-import javax.swing.JTextField;
-
-import schmitzm.lang.tree.OperationTree;
-import schmitzm.lang.tree.OperationTreeParser;
-
-/**
- * Diese Klasse stellt eine Panel zur Vefuegung, mit der eine einfache arithmetische
- * (und boolsche) Berechnungsformel eingegeben werden kann.
- * @see OperationTree
- * @see OperationTreeParser
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class OperationTreePanel extends CaptionsChangeablePanel {
-  /** Parser, der aus dem Formel-String einen Operator-Baum erstellt. */
-  private static final OperationTreeParser parser = new OperationTreeParser();
-
-  /** Speichert eine Referenz auf das Fenster-Objekt, um aus verschachtelten
-   *  Klassen einfach darauf zugreifen zu koennen. */
-  protected final OperationTreePanel THIS = this;
-
-  /** Konstante fuer den Start-Button.
-  *  @see #layoutConstraints
-  *  @see #resetCaptions(Map) */
-  public static final String START_BUTTON = OperationTreePanel.class.getName()+".StartButton";
-  /** Konstante fuer das Regel-Label.
-  *  @see #resetCaptions(Map) */
-  public static final String RULE_LABEL = OperationTreePanel.class.getName()+".RuleLabel";
-  /** Konstante fuer das Formel-Eingabefeld.
-  *  @see #layoutConstraints */
-  public static final String RULE_TEXTFIELD = OperationTreePanel.class.getName()+".RuleField";
-  /** Konstante fuer den Tooltip des Regel-Felds.
-  *  @see #resetCaptions(Map) */
-  public static final String RULE_TOOLTIP = OperationTreePanel.class.getName()+".RuleTooltip";
-  /** Konstante fuer das Operatoren-Label.
-  *  @see #resetCaptions(Map) */
-  public static final String OPERATOR_LABEL = OperationTreePanel.class.getName()+".OperatorLabel";
-  /** Konstante fuer das Operatoren-Auswahlfeld.
-  *  @see #layoutConstraints */
-  public static final String OPERATOR_COMBOBOX = OperationTreePanel.class.getName()+".OperatorBox";
-  /** Werte fuer die grafische Anordnung der Layout-Komponenten.
-   *  Ueber die Konstanten {@link #START_BUTTON}, {@link #RULE_TEXTFIELD}
-   *  und {@link #OPERATOR_COMBOBOX} koennen die Constraints (am Anfang von {@link #initGUI()})
-   *  veraendert oder erweitert werden. */
-  protected HashMap<String,GridBagConstraints> layoutConstraints = new HashMap<String,GridBagConstraints>();
-
-  /** Eingabefeld fuer die Formel. */
-  protected ManualInputOption.Text rule = null;
-  /** Butten zum Starten der Berechnung. */
-  protected JButton startButton = null;
-  /** Auswahl-Liste der zur Verfuegung stehenden Operatoren und Konstanzen. */
-  protected SelectionInputOption.Combo<String> operators = null;
-  /** Enthaelt die in der Operator-Auswahl zur Verfuegung gestellten Operatoren
-   *  Konstanten */
-  protected Vector<String>         avOperators     = new Vector<String>();
-  /** Enthaelt die in der Operator-Auswahl angezeigen Operatoren Konstanten */
-  protected HashMap<String,String> avOperatorsDesc = new HashMap<String,String>();
-  /** Enthaelt die in der Operator-Auswahl angezeigen Tooltips der Operatoren. */
-  protected 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}.
-   */
-  public OperationTreePanel() {
-    this(true);
-  }
-
-  /**
-   * Erzeugt eine neue Eingabe-GUI fuer den {@link OperationTree}.
-   * @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) {
-    super();
-    this.setPreferredSize( new Dimension(500,400) );
-    this.setLayout( new GridBagLayout() );
-
-    // Standard-Werte fuer die Layout-Anordnung hinterlegen
-    layoutConstraints.put(RULE_TEXTFIELD,    new GridBagConstraints(0,0,1,1,1.0,0.0,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0,10,5,10),0,0));
-    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 (initGUI)
-      initGUI();
-  }
-
-  /**
-   * Initalisiert die GUI des Fensters.
-   */
-  protected void initGUI() {
-    // Formel
-    rule = new ManualInputOption.Text(SwingUtil.RESOURCE.getString("Rule")+":",true,"");
-    rule.setToolTipText(SwingUtil.RESOURCE.getString("RuleToolTip"));
-    ruleTextField = (JTextField)rule.getInputComponent();
-    // neue Caret-Implementierung, damit Selektion nicht verloren geht,
-    // wenn Textfeld den Focus verliert
-    ruleTextField.setCaret( new SelectionPreservingCaret(true) );
-
-    // Button zum Starten
-    startButton = new JButton(SwingUtil.RESOURCE.getString("Calculate"));
-    startButton.addActionListener( new ActionListener() {
-      public void actionPerformed(ActionEvent e) {
-        startCalculation();
-      }
-    });
-
-    // Combo-Box fuer Operatoren
-    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]);
-      opDesc[i] = (desc == null) ? opArr[i] : desc;
-    }
-    operators = new SelectionInputOption.Combo<String>(
-      SwingUtil.RESOURCE.getString("Operators")+":",  // Label
-      true,     // keine Null-Auswahl
-      opArr,    // Operatoren
-      null,     // Default-Wert
-      opDesc,   // Angezeigte Operatoren
-      avOperatorsToolTip // Angezeigte Tooltips fuer die Operatoren
-    );
-    SwingUtil.setPreferredWidth(operators, 150);
-    operatorsComboBox = ((JComboBox)operators.getInputComponent());
-    operatorsComboBox.addActionListener( new ActionListener() {
-      public void actionPerformed(ActionEvent e) {
-        performOperatorInsert(
-            (String)operators.getValue(),
-            ruleTextField
-        );
-        // Operator-Auswahl auf "nichts" zuruecksetzen
-        operators.setValue( null );
-        // Fokus zurueck auf Formel-Feld
-        rule.grabFocus();
-      }
-    } );
-
-    // Komponenten in Fenster anordnen
-    add( rule,        layoutConstraints.get(RULE_TEXTFIELD) );
-    add( startButton, layoutConstraints.get(START_BUTTON) );
-    add( operators,   layoutConstraints.get(OPERATOR_COMBOBOX) );
-  }
-  
-  /**
-   * Kann von Sub-Klassen ueberschrieben werden, um bestimmte Operatoren
-   * in der Auswahl-Liste auszublenden.
-   * @param operator ein Operator
-   * @return immer {@code true}
-   */
-  protected boolean acceptOperator(String operator) {
-    return true;
-  }
-
-  /**
-   * 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.
-   * @param captionMap Map
-   */
-  public void resetCaptions(Map<String,Object> captionMap) {
-    super.resetCaptions(captionMap);
-    SwingUtil.resetCaption( rule.getDescriptionLabel(), captionMap.get( RULE_LABEL) );
-    SwingUtil.resetCaption( operators.getDescriptionLabel(), captionMap.get( OPERATOR_LABEL ) );
-    SwingUtil.resetCaption( startButton, captionMap.get( START_BUTTON ) );
-    Object caption = captionMap.get( RULE_TOOLTIP );
-    if ( caption != null )
-      rule.setToolTipText( caption.toString() );
-  }
-
-  /**
-   * Prueft die in der Maske spezifizierten Angaben auf Korrektheit. Ist eine
-   * Angabe nicht korrekt, wird ein entsprechender Fehler-Dialog angezeigt.
-   */
-  private boolean checkInputs() {
-    try {
-      checkInputsAndError();
-    } catch (Exception err) {
-      ExceptionDialog.show(
-          SwingUtil.getParentWindowComponent(this),
-          err,
-          (err!=null) ? err.getClass().getSimpleName() : SwingUtil.RESOURCE.getString("Error"),
-          null
-      );
-      return false;
-    }
-    return true;
-  }
-
-
-  /**
-   * Prueft die eingegebene Formel auf syntaktische Korrektheit. Unterklassen
-   * koennen diese Methode ueberschreiben, wenn die Mask
-   * @exception Exception falls ein Fehler gefunden wird
-   */
-  protected void checkInputsAndError() throws Exception {
-    parser.parse(rule.getValue());
-  }
-
-  /**
-   * Erzeugt einen {@link OperationTree} aus der Formel und wertet diese
-   * aus.
-   * @return das Ergebnis der Formel, als {@code double}-Wert
-   * @see OperationTreeParser
-   */
-  protected Object performCalculation() throws Exception {
-    return parser.parse( rule.getValue() ).evaluate();
-  }
-
-  /**
-   * Startet die Berechnung, wenn der Start-Button betaetigt wurde.
-   */
-  private void startCalculation() {
-    // Eingaben pruefen
-    if ( !checkInputs() )
-      return;
-
-    // SwingWorker erzeugen, der die Generierung durchfuehrt
-    SwingWorker worker = new SwingWorker(
-      new SwingWorker.Work() {
-        public Object execute() throws Exception {
-          performCalculation();
-          return null;
-        }
-        public void performError(Exception err) {
-          // Fehler bei der Code-Generierung verarbeiten
-          ExceptionDialog.show(
-              SwingUtil.getParentWindowComponent(THIS),
-              err,
-              (err!=null) ? err.getClass().getSimpleName() : SwingUtil.RESOURCE.getString("Error"),
-              null
-          );
-        }
-      },
-      SwingUtil.getParentFrame(this),
-      SwingUtil.RESOURCE.getString("WaitMess")
-    );
-
-    // Berechnung starten
-    worker.start();
-  }
-
-  /**
-   * Fuegt einen Operator in die aktuelle Formel ein. Ueber
-   * {@link JTextField#getSelectionStart()} und {@link JTextField#getSelectionEnd()}
-   * kann ermittelt werden, an welcher Stelle der aktuelle Cursor steht.
-   * @param op   einzufuegender Operator
-   * @param textField Text-Feld in das der Operator eingefuegt werden soll
-   * @see JTextField#getSelectedText()
-   */
-  protected void performOperatorInsert(String op, JTextField textField) {
-    int selStart     = textField.getSelectionStart();
-    int selEnd       = textField.getSelectionEnd();
-    String selection = textField.getSelectedText();
-
-    // Anzahl an geklammerten Parametern fuer den Operator ermitteln
-    int parameterCount = getParameterCount(op);
-
-    // Bei mehr-stelligen Funktionen, erhaelt die Funktion den selektierten
-    // Bereich als ersten Operand
-    if ( parameterCount >= 1 ) {
-      // wenn nichts selektiert war, wird "_" fuer den Operanden
-      // vorgeblendet
-      if ( selection == null )
-        selection = "_";
-      // Operator um die Parameter erweitern
-      op = op + "( " + selection;
-      for (int i=1; i<parameterCount; i++)
-        op = op + ", _";
-      op = op + " )";
-    }
-
-    // Selektierten Bereich ersetzen (wenn nichts selektiert war, wird autom.
-    // nur eingefuegt)
-    textField.replaceSelection( op );
-
-    // Wenn vorher ein Bereich ausgewaehlt war, wird nun der
-    // neue Operator ausgewaehlt
-    if ( selStart < selEnd ) {
-      textField.setSelectionStart( selStart );
-      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;
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
+
+import java.awt.Dimension;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JTextField;
+
+import schmitzm.lang.tree.OperationTree;
+import schmitzm.lang.tree.OperationTreeParser;
+
+/**
+ * Diese Klasse stellt eine Panel zur Vefuegung, mit der eine einfache arithmetische
+ * (und boolsche) Berechnungsformel eingegeben werden kann.
+ * @see OperationTree
+ * @see OperationTreeParser
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class OperationTreePanel extends CaptionsChangeablePanel {
+  /** Parser, der aus dem Formel-String einen Operator-Baum erstellt. */
+  private static final OperationTreeParser parser = new OperationTreeParser();
+
+  /** Speichert eine Referenz auf das Fenster-Objekt, um aus verschachtelten
+   *  Klassen einfach darauf zugreifen zu koennen. */
+  protected final OperationTreePanel THIS = this;
+
+  /** Konstante fuer den Start-Button.
+  *  @see #layoutConstraints
+  *  @see #resetCaptions(Map) */
+  public static final String START_BUTTON = OperationTreePanel.class.getName()+".StartButton";
+  /** Konstante fuer das Regel-Label.
+  *  @see #resetCaptions(Map) */
+  public static final String RULE_LABEL = OperationTreePanel.class.getName()+".RuleLabel";
+  /** Konstante fuer das Formel-Eingabefeld.
+  *  @see #layoutConstraints */
+  public static final String RULE_TEXTFIELD = OperationTreePanel.class.getName()+".RuleField";
+  /** Konstante fuer den Tooltip des Regel-Felds.
+  *  @see #resetCaptions(Map) */
+  public static final String RULE_TOOLTIP = OperationTreePanel.class.getName()+".RuleTooltip";
+  /** Konstante fuer das Operatoren-Label.
+  *  @see #resetCaptions(Map) */
+  public static final String OPERATOR_LABEL = OperationTreePanel.class.getName()+".OperatorLabel";
+  /** Konstante fuer das Operatoren-Auswahlfeld.
+  *  @see #layoutConstraints */
+  public static final String OPERATOR_COMBOBOX = OperationTreePanel.class.getName()+".OperatorBox";
+  /** Werte fuer die grafische Anordnung der Layout-Komponenten.
+   *  Ueber die Konstanten {@link #START_BUTTON}, {@link #RULE_TEXTFIELD}
+   *  und {@link #OPERATOR_COMBOBOX} koennen die Constraints (am Anfang von {@link #initGUI()})
+   *  veraendert oder erweitert werden. */
+  protected HashMap<String,GridBagConstraints> layoutConstraints = new HashMap<String,GridBagConstraints>();
+
+  /** Eingabefeld fuer die Formel. */
+  protected ManualInputOption.Text rule = null;
+  /** Butten zum Starten der Berechnung. */
+  protected JButton startButton = null;
+  /** Auswahl-Liste der zur Verfuegung stehenden Operatoren und Konstanzen. */
+  protected SelectionInputOption.Combo<String> operators = null;
+  /** Enthaelt die in der Operator-Auswahl zur Verfuegung gestellten Operatoren
+   *  Konstanten */
+  protected Vector<String>         avOperators     = new Vector<String>();
+  /** Enthaelt die in der Operator-Auswahl angezeigen Operatoren Konstanten */
+  protected HashMap<String,String> avOperatorsDesc = new HashMap<String,String>();
+  /** Enthaelt die in der Operator-Auswahl angezeigen Tooltips der Operatoren. */
+  protected 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}.
+   */
+  public OperationTreePanel() {
+    this(true);
+  }
+
+  /**
+   * Erzeugt eine neue Eingabe-GUI fuer den {@link OperationTree}.
+   * @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) {
+    super();
+    this.setPreferredSize( new Dimension(500,400) );
+    this.setLayout( new GridBagLayout() );
+
+    // Standard-Werte fuer die Layout-Anordnung hinterlegen
+    layoutConstraints.put(RULE_TEXTFIELD,    new GridBagConstraints(0,0,1,1,1.0,0.0,GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(0,10,5,10),0,0));
+    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 (initGUI)
+      initGUI();
+  }
+
+  /**
+   * Initalisiert die GUI des Fensters.
+   */
+  protected void initGUI() {
+    // Formel
+    rule = new ManualInputOption.Text(SwingUtil.RESOURCE.getString("Rule")+":",true,"");
+    rule.setToolTipText(SwingUtil.RESOURCE.getString("RuleToolTip"));
+    ruleTextField = (JTextField)rule.getInputComponent();
+    // neue Caret-Implementierung, damit Selektion nicht verloren geht,
+    // wenn Textfeld den Focus verliert
+    ruleTextField.setCaret( new SelectionPreservingCaret(true) );
+
+    // Button zum Starten
+    startButton = new JButton(SwingUtil.RESOURCE.getString("Calculate"));
+    startButton.addActionListener( new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        startCalculation();
+      }
+    });
+
+    // Combo-Box fuer Operatoren
+    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]);
+      opDesc[i] = (desc == null) ? opArr[i] : desc;
+    }
+    operators = new SelectionInputOption.Combo<String>(
+      SwingUtil.RESOURCE.getString("Operators")+":",  // Label
+      true,     // keine Null-Auswahl
+      opArr,    // Operatoren
+      null,     // Default-Wert
+      opDesc,   // Angezeigte Operatoren
+      avOperatorsToolTip // Angezeigte Tooltips fuer die Operatoren
+    );
+    SwingUtil.setPreferredWidth(operators, 150);
+    operatorsComboBox = ((JComboBox)operators.getInputComponent());
+    operatorsComboBox.addActionListener( new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        performOperatorInsert(
+            (String)operators.getValue(),
+            ruleTextField
+        );
+        // Operator-Auswahl auf "nichts" zuruecksetzen
+        operators.setValue( null );
+        // Fokus zurueck auf Formel-Feld
+        rule.grabFocus();
+      }
+    } );
+
+    // Komponenten in Fenster anordnen
+    add( rule,        layoutConstraints.get(RULE_TEXTFIELD) );
+    add( startButton, layoutConstraints.get(START_BUTTON) );
+    add( operators,   layoutConstraints.get(OPERATOR_COMBOBOX) );
+  }
+  
+  /**
+   * Kann von Sub-Klassen ueberschrieben werden, um bestimmte Operatoren
+   * in der Auswahl-Liste auszublenden.
+   * @param operator ein Operator
+   * @return immer {@code true}
+   */
+  protected boolean acceptOperator(String operator) {
+    return true;
+  }
+
+  /**
+   * 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.
+   * @param captionMap Map
+   */
+  public void resetCaptions(Map<String,Object> captionMap) {
+    super.resetCaptions(captionMap);
+    SwingUtil.resetCaption( rule.getDescriptionLabel(), captionMap.get( RULE_LABEL) );
+    SwingUtil.resetCaption( operators.getDescriptionLabel(), captionMap.get( OPERATOR_LABEL ) );
+    SwingUtil.resetCaption( startButton, captionMap.get( START_BUTTON ) );
+    Object caption = captionMap.get( RULE_TOOLTIP );
+    if ( caption != null )
+      rule.setToolTipText( caption.toString() );
+  }
+
+  /**
+   * Prueft die in der Maske spezifizierten Angaben auf Korrektheit. Ist eine
+   * Angabe nicht korrekt, wird ein entsprechender Fehler-Dialog angezeigt.
+   */
+  private boolean checkInputs() {
+    try {
+      checkInputsAndError();
+    } catch (Exception err) {
+      ExceptionDialog.show(
+          SwingUtil.getParentWindowComponent(this),
+          err,
+          (err!=null) ? err.getClass().getSimpleName() : SwingUtil.RESOURCE.getString("Error"),
+          null
+      );
+      return false;
+    }
+    return true;
+  }
+
+
+  /**
+   * Prueft die eingegebene Formel auf syntaktische Korrektheit. Unterklassen
+   * koennen diese Methode ueberschreiben, wenn die Mask
+   * @exception Exception falls ein Fehler gefunden wird
+   */
+  protected void checkInputsAndError() throws Exception {
+    parser.parse(rule.getValue());
+  }
+
+  /**
+   * Erzeugt einen {@link OperationTree} aus der Formel und wertet diese
+   * aus.
+   * @return das Ergebnis der Formel, als {@code double}-Wert
+   * @see OperationTreeParser
+   */
+  protected Object performCalculation() throws Exception {
+    return parser.parse( rule.getValue() ).evaluate();
+  }
+
+  /**
+   * Startet die Berechnung, wenn der Start-Button betaetigt wurde.
+   */
+  private void startCalculation() {
+    // Eingaben pruefen
+    if ( !checkInputs() )
+      return;
+
+    // SwingWorker erzeugen, der die Generierung durchfuehrt
+    SwingWorker worker = new SwingWorker(
+      new SwingWorker.Work() {
+        public Object execute() throws Exception {
+          performCalculation();
+          return null;
+        }
+        public void performError(Exception err) {
+          // Fehler bei der Code-Generierung verarbeiten
+          ExceptionDialog.show(
+              SwingUtil.getParentWindowComponent(THIS),
+              err,
+              (err!=null) ? err.getClass().getSimpleName() : SwingUtil.RESOURCE.getString("Error"),
+              null
+          );
+        }
+      },
+      SwingUtil.getParentFrame(this),
+      SwingUtil.RESOURCE.getString("WaitMess")
+    );
+
+    // Berechnung starten
+    worker.start();
+  }
+
+  /**
+   * Fuegt einen Operator in die aktuelle Formel ein. Ueber
+   * {@link JTextField#getSelectionStart()} und {@link JTextField#getSelectionEnd()}
+   * kann ermittelt werden, an welcher Stelle der aktuelle Cursor steht.
+   * @param op   einzufuegender Operator
+   * @param textField Text-Feld in das der Operator eingefuegt werden soll
+   * @see JTextField#getSelectedText()
+   */
+  protected void performOperatorInsert(String op, JTextField textField) {
+    int selStart     = textField.getSelectionStart();
+    int selEnd       = textField.getSelectionEnd();
+    String selection = textField.getSelectedText();
+
+    // Anzahl an geklammerten Parametern fuer den Operator ermitteln
+    int parameterCount = getParameterCount(op);
+
+    // Bei mehr-stelligen Funktionen, erhaelt die Funktion den selektierten
+    // Bereich als ersten Operand
+    if ( parameterCount >= 1 ) {
+      // wenn nichts selektiert war, wird "_" fuer den Operanden
+      // vorgeblendet
+      if ( selection == null )
+        selection = "_";
+      // Operator um die Parameter erweitern
+      op = op + "( " + selection;
+      for (int i=1; i<parameterCount; i++)
+        op = op + ", _";
+      op = op + " )";
+    }
+
+    // Selektierten Bereich ersetzen (wenn nichts selektiert war, wird autom.
+    // nur eingefuegt)
+    textField.replaceSelection( op );
+
+    // Wenn vorher ein Bereich ausgewaehlt war, wird nun der
+    // neue Operator ausgewaehlt
+    if ( selStart < selEnd ) {
+      textField.setSelectionStart( selStart );
+      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: trunk/src/schmitzm/swing/RotationSpinnerNumberModel.java
===================================================================
--- trunk/src/schmitzm/swing/RotationSpinnerNumberModel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/RotationSpinnerNumberModel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,118 +1,136 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing;
-
-import javax.swing.SpinnerNumberModel;
-
-/**
- * Diese Klasse erweitert das {@link RotationSpinnerNumberModel} um eine
- * Rotation-Funktionalitaet. Ist diese eingeschaltet, wechselt der Spinner
- * automatisch auf den kleinsten Wert, wenn der Maximum-Wert ueberschritten
- * wird (und umgekehrt).
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class RotationSpinnerNumberModel extends SpinnerNumberModel {
-  /** Flag fuer die Rotation-Funktionalitaet. */
-  protected boolean rotation = false;
-
-  /**
-   * Erzeugt ein neues Model.
-   * @param value    initialer Wert
-   * @param minimum  Minimal-Wert
-   * @param maximum  Maximal-Wert
-   * @param stepSize Schrittweite
-   * @param rotation falls {@code true} wechselt der Spinner auf den kleinsten Wert
-   *                 wenn der Maximalwert ueberschritten wird (und umgekehrt)
-   */
-  public RotationSpinnerNumberModel(Number value, Comparable minimum, Comparable maximum, Number stepSize, boolean rotation) {
-    super(value, minimum, maximum, stepSize);
-    setRotation(rotation);
-  }
-
-  /**
-   * Erzeugt ein neues Model.
-   * @param value    initialer Wert
-   * @param minimum  Minimal-Wert
-   * @param maximum  Maximal-Wert
-   * @param stepSize Schrittweite
-   * @param rotation falls {@code true} wechselt der Spinner auf den kleinsten Wert
-   *                 wenn der Maximalwert ueberschritten wird (und umgekehrt)
-   */
-  public RotationSpinnerNumberModel(int value, int minimum, int maximum, int stepSize, boolean rotation) {
-    super(value, minimum, maximum, stepSize);
-    setRotation(rotation);
-  }
-
-  /**
-   * Erzeugt ein neues Model.
-   * @param value    initialer Wert
-   * @param minimum  Minimal-Wert
-   * @param maximum  Maximal-Wert
-   * @param stepSize Schrittweite
-   * @param rotation falls {@code true} wechselt der Spinner auf den kleinsten Wert
-   *                 wenn der Maximalwert ueberschritten wird (und umgekehrt)
-   */
-  public RotationSpinnerNumberModel(double value, double minimum, double maximum, double stepSize, boolean rotation) {
-    super(value, minimum, maximum, stepSize);
-    setRotation(rotation);
-  }
-
-  /**
-   * Erzeugt ein neues Model ohne Minimum- und Maximumwert.
-   */
-  public RotationSpinnerNumberModel() {
-    super();
-    setRotation( false );
-  }
-
-  /**
-   * Liefert den naechst-groesseren Wert.
-   * @return {@link #getMinimum()} wenn der Maximalwert erreicht ist und
-   *         die Rotation-Funktion eingestellt ist
-   * @see #setRotation(boolean)
-   */
-  public Object getNextValue() {
-    Object next = super.getNextValue();
-    if ( next == null && rotation )
-      next = getMinimum();
-    return next;
-  }
-
-  /**
-   * Liefert den naechst-kleineren Wert.
-   * @return {@link #getMaximum()} wenn der Minimalwert erreicht ist und
-   *         die Rotation-Funktion eingestellt ist
-   * @see #setRotation(boolean)
-   */
-  public Object getPreviousValue() {
-    Object next = super.getPreviousValue();
-    if ( next == null && rotation )
-      next = getMaximum();
-    return next;
-  }
-
-  /**
-   * (De)aktiviert die Rotation-Funktion.
-   * @param rotation wenn {@code true} wird, die Rotation-Funktion aktiviert
-   */
-  public void setRotation(boolean rotation) {
-    this.rotation = rotation;
-  }
-
-  /**
-   * Prueft, ob die Rotation-Funktion aktiviert ist.
-   */
-  public boolean getRotation() {
-    return this.rotation;
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
+
+import javax.swing.SpinnerNumberModel;
+
+/**
+ * Diese Klasse erweitert das {@link RotationSpinnerNumberModel} um eine
+ * Rotation-Funktionalitaet. Ist diese eingeschaltet, wechselt der Spinner
+ * automatisch auf den kleinsten Wert, wenn der Maximum-Wert ueberschritten
+ * wird (und umgekehrt).
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class RotationSpinnerNumberModel extends SpinnerNumberModel {
+  /** Flag fuer die Rotation-Funktionalitaet. */
+  protected boolean rotation = false;
+
+  /**
+   * Erzeugt ein neues Model.
+   * @param value    initialer Wert
+   * @param minimum  Minimal-Wert
+   * @param maximum  Maximal-Wert
+   * @param stepSize Schrittweite
+   * @param rotation falls {@code true} wechselt der Spinner auf den kleinsten Wert
+   *                 wenn der Maximalwert ueberschritten wird (und umgekehrt)
+   */
+  public RotationSpinnerNumberModel(Number value, Comparable minimum, Comparable maximum, Number stepSize, boolean rotation) {
+    super(value, minimum, maximum, stepSize);
+    setRotation(rotation);
+  }
+
+  /**
+   * Erzeugt ein neues Model.
+   * @param value    initialer Wert
+   * @param minimum  Minimal-Wert
+   * @param maximum  Maximal-Wert
+   * @param stepSize Schrittweite
+   * @param rotation falls {@code true} wechselt der Spinner auf den kleinsten Wert
+   *                 wenn der Maximalwert ueberschritten wird (und umgekehrt)
+   */
+  public RotationSpinnerNumberModel(int value, int minimum, int maximum, int stepSize, boolean rotation) {
+    super(value, minimum, maximum, stepSize);
+    setRotation(rotation);
+  }
+
+  /**
+   * Erzeugt ein neues Model.
+   * @param value    initialer Wert
+   * @param minimum  Minimal-Wert
+   * @param maximum  Maximal-Wert
+   * @param stepSize Schrittweite
+   * @param rotation falls {@code true} wechselt der Spinner auf den kleinsten Wert
+   *                 wenn der Maximalwert ueberschritten wird (und umgekehrt)
+   */
+  public RotationSpinnerNumberModel(double value, double minimum, double maximum, double stepSize, boolean rotation) {
+    super(value, minimum, maximum, stepSize);
+    setRotation(rotation);
+  }
+
+  /**
+   * Erzeugt ein neues Model ohne Minimum- und Maximumwert.
+   */
+  public RotationSpinnerNumberModel() {
+    super();
+    setRotation( false );
+  }
+
+  /**
+   * Liefert den naechst-groesseren Wert.
+   * @return {@link #getMinimum()} wenn der Maximalwert erreicht ist und
+   *         die Rotation-Funktion eingestellt ist
+   * @see #setRotation(boolean)
+   */
+  public Object getNextValue() {
+    Object next = super.getNextValue();
+    if ( next == null && rotation )
+      next = getMinimum();
+    return next;
+  }
+
+  /**
+   * Liefert den naechst-kleineren Wert.
+   * @return {@link #getMaximum()} wenn der Minimalwert erreicht ist und
+   *         die Rotation-Funktion eingestellt ist
+   * @see #setRotation(boolean)
+   */
+  public Object getPreviousValue() {
+    Object next = super.getPreviousValue();
+    if ( next == null && rotation )
+      next = getMaximum();
+    return next;
+  }
+
+  /**
+   * (De)aktiviert die Rotation-Funktion.
+   * @param rotation wenn {@code true} wird, die Rotation-Funktion aktiviert
+   */
+  public void setRotation(boolean rotation) {
+    this.rotation = rotation;
+  }
+
+  /**
+   * Prueft, ob die Rotation-Funktion aktiviert ist.
+   */
+  public boolean getRotation() {
+    return this.rotation;
+  }
+}

Modified: trunk/src/schmitzm/swing/SelectableJTable.java
===================================================================
--- trunk/src/schmitzm/swing/SelectableJTable.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/SelectableJTable.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,113 +1,132 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.swing;
-
-import java.util.Vector;
-
-import javax.swing.JTable;
-import javax.swing.ListSelectionModel;
-import javax.swing.table.TableColumnModel;
-import javax.swing.table.TableModel;
-
-import schmitzm.swing.table.SelectionTableModel;
-
-/**
- * Extends the {@link JTable} by redefining the {@link #changeSelection(int, int, boolean, boolean)}
- * method. If a {@link SelectionTableModel} is used, a click on the selection column must not
- * clear an existing selection.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- */
-public class SelectableJTable extends JTable {
-  /**
-   * Creates an empty table.
-   */
-  public SelectableJTable() {
-    super();
-    initTable();
-  }
-
-  /**
-   * Creates an empty table.
-   */
-  public SelectableJTable(int numRows, int numColumns) {
-    super(numRows, numColumns);
-    initTable();
-  }
-
-  /**
-   * Creates a new table.
-   */
-  public SelectableJTable(Object[][] rowData, Object[] columnNames) {
-    super(rowData, columnNames);
-    initTable();
-  }
-
-  /**
-   * Creates a new table.
-   */
-  public SelectableJTable(TableModel dm, TableColumnModel cm, ListSelectionModel sm) {
-    super(dm, cm, sm);
-    initTable();
-  }
-
-  /**
-   * Creates a new table.
-   */
-  public SelectableJTable(TableModel dm, TableColumnModel cm) {
-    super(dm, cm);
-    initTable();
-  }
-
-  /**
-   * Creates a new table.
-   */
-  public SelectableJTable(TableModel dm) {
-    super(dm);
-    initTable();
-  }
-
-  /**
-   * Creates a new table.
-   */
-  public SelectableJTable(Vector rowData, Vector columnNames) {
-    super(rowData, columnNames);
-    initTable();
-  }
-
-  /**
-   * Called by every constructor to initialize the extended
-   * functionalities. Currently does nothing.
-   */
-  protected void initTable() {
-  }
-
-  /**
-   * If a {@link SelectionTableModel} is used, a click on the selection column must not
-   * clear an existing selection. So if ...
-   * <ul>
-   *   <li>{@link #getModel()} is an {@link SelectionTableModel}
-   *   <li>{@code toggle} flag is {@code false}</li>
-   *   <li>{@code extend} flag is {@code false}</li>
-   *   <li>{@link #convertColumnIndexToModel(int) convertColumnIndexToModel(col)} is 0
-   * </ul>
-   * ... this method sets {@code toggle} to {@code true} (before calling the super-method)
-   * to simulate that the Strg/Ctrl-key is pressed.
-   */
-  @Override
-  public void changeSelection(int row, int col, boolean toggle, boolean extend) {
-    if ( getModel() instanceof SelectionTableModel &&
-         convertColumnIndexToModel(col) == 0 &&
-         !toggle &&
-         !extend )
-      toggle = true;
-    super.changeSelection(row, col, toggle, extend);
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
+
+import java.util.Vector;
+
+import javax.swing.JTable;
+import javax.swing.ListSelectionModel;
+import javax.swing.table.TableColumnModel;
+import javax.swing.table.TableModel;
+
+import schmitzm.swing.table.SelectionTableModel;
+
+/**
+ * Extends the {@link JTable} by redefining the {@link #changeSelection(int, int, boolean, boolean)}
+ * method. If a {@link SelectionTableModel} is used, a click on the selection column must not
+ * clear an existing selection.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ */
+public class SelectableJTable extends JTable {
+  /**
+   * Creates an empty table.
+   */
+  public SelectableJTable() {
+    super();
+    initTable();
+  }
+
+  /**
+   * Creates an empty table.
+   */
+  public SelectableJTable(int numRows, int numColumns) {
+    super(numRows, numColumns);
+    initTable();
+  }
+
+  /**
+   * Creates a new table.
+   */
+  public SelectableJTable(Object[][] rowData, Object[] columnNames) {
+    super(rowData, columnNames);
+    initTable();
+  }
+
+  /**
+   * Creates a new table.
+   */
+  public SelectableJTable(TableModel dm, TableColumnModel cm, ListSelectionModel sm) {
+    super(dm, cm, sm);
+    initTable();
+  }
+
+  /**
+   * Creates a new table.
+   */
+  public SelectableJTable(TableModel dm, TableColumnModel cm) {
+    super(dm, cm);
+    initTable();
+  }
+
+  /**
+   * Creates a new table.
+   */
+  public SelectableJTable(TableModel dm) {
+    super(dm);
+    initTable();
+  }
+
+  /**
+   * Creates a new table.
+   */
+  public SelectableJTable(Vector rowData, Vector columnNames) {
+    super(rowData, columnNames);
+    initTable();
+  }
+
+  /**
+   * Called by every constructor to initialize the extended
+   * functionalities. Currently does nothing.
+   */
+  protected void initTable() {
+  }
+
+  /**
+   * If a {@link SelectionTableModel} is used, a click on the selection column must not
+   * clear an existing selection. So if ...
+   * <ul>
+   *   <li>{@link #getModel()} is an {@link SelectionTableModel}
+   *   <li>{@code toggle} flag is {@code false}</li>
+   *   <li>{@code extend} flag is {@code false}</li>
+   *   <li>{@link #convertColumnIndexToModel(int) convertColumnIndexToModel(col)} is 0
+   * </ul>
+   * ... this method sets {@code toggle} to {@code true} (before calling the super-method)
+   * to simulate that the Strg/Ctrl-key is pressed.
+   */
+  @Override
+  public void changeSelection(int row, int col, boolean toggle, boolean extend) {
+    if ( getModel() instanceof SelectionTableModel &&
+         convertColumnIndexToModel(col) == 0 &&
+         !toggle &&
+         !extend )
+      toggle = true;
+    super.changeSelection(row, col, toggle, extend);
+  }
+}

Modified: trunk/src/schmitzm/swing/SelectionInputOption.java
===================================================================
--- trunk/src/schmitzm/swing/SelectionInputOption.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/SelectionInputOption.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,594 +1,612 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing;
-
-import java.awt.Component;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.ItemEvent;
-import java.awt.event.ItemListener;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Vector;
-
-import javax.swing.BoxLayout;
-import javax.swing.Icon;
-import javax.swing.JComboBox;
-import javax.swing.JList;
-import javax.swing.JRadioButton;
-import javax.swing.plaf.basic.BasicComboBoxRenderer;
-
-/**
- * Diese Klasse stellt eine Auswahl-Eingabe-Option fuer das {@link MultipleOptionPane}
- * dar. Die Klasse kann nicht direkt instanziiert werden.
- * Statt dessen sind die eingebetteten Klassen
- * <ul>
- * <li>{@link SelectionInputOption.Combo SelectionInputOption.Combo}</li>
- * </ul>
- * zu verwenden.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public abstract class SelectionInputOption<E> extends InputOption<E> {
-  /** Speichert die Objekte, die zur Auswahl stehen. */
-  protected E[] selectionObject = null;
-  /** Speichert die Objekte, die fuer die Auswahl angezeigt werden. */
-  protected Object[] displayObject   = null;
-  /** Speichert fuer jedes {@link #selectionObject} einen ToolTip, der
-   *  fuer das Auswahl-Objekt angezeigt wird. */
-  protected Map<Object,String> displayToolTip  = new HashMap<Object, String>();
-
-  /**
-   * Erzeugt eine neue Eingabe-Option.
-   * @param label       Beschreibung
-   * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
-   * @param value       die zur Auswahl stehenden Objekte
-   * @param defIdx      Index der vorgeblendeten Auswahl
-   * @param display     die anstelle der Auswahl-Objekte angezeigten Objekte
-   *                    (kann <code>null</code> sein)
-   * @exception IllegalArgumentException falls sich die Array-Groessen von
-   *            <code>value</code> und <code>display</code> unterscheiden
-   */
-  protected SelectionInputOption(String label, boolean inputNeeded, E[] value, int defIdx, Object[] display) {
-    super(label,inputNeeded);
-    // Referenz auf Objekte merken und Komponente befuellen
-    setSelectionObjects(value,display);
-    setSelectedIndex(defIdx);
-  }
-
-  /**
-   * Erzeugt eine neue Eingabe-Option.
-   * @param label       Beschreibung
-   * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
-   * @param value       die zur Auswahl stehenden Objekte
-   * @param defValue    vorgeblendetes Auswahlobjekt
-   * @param display     die anstelle der Auswahl-Objekte angezeigten Objekte
-   *                    (kann <code>null</code> sein)
-   * @exception IllegalArgumentException falls sich die Array-Groessen von
-   *            <code>value</code> und <code>display</code> unterscheiden
-   */
-  protected SelectionInputOption(String label, boolean inputNeeded, E[] value, E defValue, Object[] display) {
-    this(label,inputNeeded,value,defValue,display,null);
-  }
-
-  /**
-   * Erzeugt eine neue Eingabe-Option.
-   * @param label       Beschreibung
-   * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
-   * @param value       die zur Auswahl stehenden Objekte
-   * @param defValue    vorgeblendetes Auswahlobjekt
-   * @param display     die anstelle der Auswahl-Objekte angezeigten Objekte
-   *                    (kann <code>null</code> sein)
-   * @param tooltip     die fuer jedes Auswahl-Objekt angezeigten Tooltips
-   *                    (kann <code>null</code> sein)
-   * @exception IllegalArgumentException falls sich die Array-Groessen von
-   *            <code>value</code> und <code>display</code> unterscheiden
-   */
-  protected SelectionInputOption(String label, boolean inputNeeded, E[] value, E defValue, Object[] display, Map<Object,String> tooltip) {
-    super(label,inputNeeded);
-    // Referenz auf Objekte merken und Komponente befuellen
-    setSelectionObjects(value,display,tooltip);
-    setSelectedItem(defValue);
-  }
-
-  /**
-   * Erzeugt eine neue Eingabe-Option. Es wird (sofern vorhanden) das erste
-   * Auswahl-Objekt vorgeblendet.
-   * @param label       Beschreibung
-   * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
-   * @param value       die zur Auswahl stehenden Objekte
-   * @param display     die anstelle der Auswahl-Objekte angezeigten Objekte
-   *                    (kann <code>null</code> sein)
-   * @exception IllegalArgumentException falls sich die Array-Groessen von
-   *            <code>value</code> und <code>display</code> unterscheiden
-   */
-  protected SelectionInputOption(String label, boolean inputNeeded, E[] value, Object[] display) {
-    this(label,inputNeeded,value,value.length > 0 ? 0 : -1, display);
-  }
-
-  /**
-   * Setzt die im Auswahlfeld zur Verfuegung stehenden Eintraege
-   * @param value       die zur Auswahl stehenden Objekte
-   * @param display     die anstelle der Auswahl-Objekte angezeigten Objekte
-   *                    (kann <code>null</code> sein)
-   * @exception IllegalArgumentException falls sich die Array-Groessen von
-   *            <code>value</code> und <code>display</code> unterscheiden
-   *
-   */
-  public void setSelectionObjects(E[] value, Object[] display) {
-    setSelectionObjects(value,display,null);
-  }
-  
-  /**
-   * Setzt die im Auswahlfeld zur Verfuegung stehenden Eintraege
-   * @param value       die zur Auswahl stehenden Objekte
-   * @param display     die anstelle der Auswahl-Objekte angezeigten Objekte
-   *                    (kann <code>null</code> sein)
-   * @param tooltip     die fuer jedes Auswahl-Objekt angezeigten Tooltips
-   *                    (kann <code>null</code> sein)
-   * @exception IllegalArgumentException falls sich die Array-Groessen von
-   *            <code>value</code> und <code>display</code> unterscheiden
-   *
-   */
-  public void setSelectionObjects(E[] value, Object[] display, Map<Object,String> tooltip) {
-    // werden keine Wert angegeben, wird dies wie eine leere
-    // Menge behandelt
-    if (value == null)
-      value = (E[])new Object[0];
-    // Wurden keine speziellen Anzeigewerte angegeben, werden die
-    // Auswahl-Objekte verwendet
-    if (display == null)
-      display = value;
-    // Haben der Auswahl- und der Anzeige-Array unterschiedliche
-    // Laenge, wird dies nicht akzeptiert
-    if ( ( (Object[]) display).length != ( (E[]) value).length)
-      throw new IllegalArgumentException("display-Array and value-Array must have the same size!");
-
-    Object lastSelection = getValue();
-    this.selectionObject = value;
-    this.displayObject   = display;
-    this.displayToolTip  = tooltip;
-    performSelectionUpdate();
-    setSelectedItem(lastSelection);
-  }
-
-  /**
-   * Aktualisiert die Objekte in der der Auswahlkomponente. Wird aufgerufen,
-   * wenn dich die zur Auswahl stehenden Objekte aendern. Die Variablen
-   * {@link #selectionObject} und {@link #displayObject} sind dann bereits
-   * aktualisiert,
-   */
-  protected abstract void performSelectionUpdate();
-
-  /**
-   * Liefert immer <code>true</code>, da keine speziellen Anforderungen
-   * an die Auswahl-Eingabe gestellt werden.
-   */
-  protected boolean performIsInputValid() {
-    return true;
-  }
-
-  /**
-   * Prueft, ob im Auswahlfeld ein Eintrag ausgewaehlt wurde.
-   */
-  protected boolean performIsInputEmpty() {
-    return getSelectedIndex() < 0;
-  }
-
-  /**
-   * Liefert das Objekt, das zum aktuell ausgewaehlten Eintrag der
-   * Auswahl-Liste gehoert.
-   * @return <code>null</code> falls kein Objekt ausgewaehlt ist
-   */
-  protected E performGetValue() {
-    int idx = getSelectedIndex();
-    return idx < 0 ? null : selectionObject[getSelectedIndex()];
-  }
-
-  /**
-   * Setzt das Objekt, das in der Auswahlliste angewaehlt wird. Ruft
-   * {@link #setSelectedItem(Object)} auf.
-   * @return immer <code>true</code>
-   */
-  protected boolean performSetValue(E newValue) {
-    setSelectedItem(newValue);
-    return true;
-  }
-
-  /**
-   * Setzt einen neuen Wert, mit der die Eingabe-Option belegt wird.
-   * Ruft lediglich {@link #performSetValue(Object)} auf. Ueberschreibt die
-   * Methode von {@link InputOption}, da die Ueberpruefung auf Aenderung
-   * (und Event-Ausloesung) in {@link #setSelectedIndex(int)} erfolgt.
-   * @param newValue neuer Wert
-   * @return <code>false</code> gdw. der Objekt-Typ fuer die Option nicht
-   *         zulaessig ist
-   */
-  public boolean setValue(E newValue) {
-    if ( !performSetValue(newValue) )
-      return false;
-    return true;
-  }
-
-  /**
-   * Liefert den Index, der in der Objekt-Liste ausgewaehlt wurde.
-   * @return <code>-1</code> falls kein Objekt ausgewaehlt wurde
-   */
-  public abstract int getSelectedIndex();
-
-  /**
-   * Setzt den Index, der in der Objekt-Liste ausgewaehlt wurde. <b>Da dies die
-   * Basis-Methode fuer alle Aenderungsoperationen darstellt, muss sie
-   * die Ueberpruefung auf Aenderung implementieren und ggf.
-   * {@link #fireOptionChanged(Object,Object)} ausloesen.</b>
-   * @param idx Listen-Index (-1 um eine Leer-Auswahl zu erzeugen)
-   */
-  public abstract void setSelectedIndex(int idx);
-
-  /**
-   * Setzt die Auswahl auf ein bestimmtes Objekt. Ist dieses nicht vorhanden,
-   * wird die Auswahlliste auf eine leere Auswahl eingestellt.
-   */
-  public void setSelectedItem(Object object) {
-    // altes Object in der neuen Objektliste suchen
-    int newIdx = -1;
-    for (int i=0; i<selectionObject.length && newIdx < 0; i++)
-//      if ( selectionObject[i] == object )
-      if ( selectionObject[i]==null && object==null ||
-           selectionObject[i]!=null && selectionObject[i].equals(object) )
-        newIdx = i;
-    setSelectedIndex(newIdx);
-  }
-
-  /**
-   * Liefert das Anzeige-Objekt der akuellen Auswahl.
-   */
-  public Object getSelectedDisplayItem() {
-    // altes Object in der neuen Objektliste suchen
-    if ( getSelectedIndex() >= 0 )
-      return displayObject[ getSelectedIndex() ];
-   return null;
-  }
-
-  /**
-   * Setzt die Auswahl auf ein bestimmtes Anzeige-Objekt. Ist dieses nicht vorhanden,
-   * wird die Auswahlliste auf eine leere Auswahl eingestellt.
-   */
-  public void setSelectedDisplayItem(Object object) {
-    // altes Object in der neuen Objektliste suchen
-    int newIdx = -1;
-    for (int i=0; i<displayObject.length && newIdx < 0; i++)
-//      if ( selectionObject[i] == object )
-      if ( displayObject[i]==null && object==null ||
-           displayObject[i]!=null && displayObject[i].equals(object) )
-        newIdx = i;
-    setSelectedIndex(newIdx);
-  }
-
-  /**
-   * Liefert die Anzahl der zur Auswahl stehenden Eintraege.
-   */
-  public int getSelectedItemCount() {
-    return selectionObject != null ? selectionObject.length : 0;
-  }
-
-  /**
-   * Diese Klasse stellt eine Auswahl-Option dar, die durch eine
-   * {@link JComboBox} dargestellt wird.
-   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-   * @version 1.0
-   */
-  public static class Combo<E> extends SelectionInputOption {
-    /**
-     * Erzeugt eine neue Auswahl-Option.
-     * @param label       Beschreibung
-     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
-     * @param value       die zur Auswahl stehenden Objekte
-     * @param defIdx      Index der vorgeblendeten Auswahl
-     * @param display     die anstelle der Auswahl-Objekte angezeigten Objekte
-     *                    (kann <code>null</code> sein)
-     * @exception IllegalArgumentException falls sich die Array-Groessen von
-     *            <code>value</code> und <code>display</code> unterscheiden
-     */
-    public Combo(String label, boolean inputNeeded, E[] value, int defIdx, Object[] display) {
-      super(label,inputNeeded,value,defIdx, display);
-    }
-
-    /**
-     * Erzeugt eine neue Auswahl-Option.
-     * @param label       Beschreibung
-     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
-     * @param value       die zur Auswahl stehenden Objekte
-     * @param defValue    vorgeblendetes Auswahlobjekt
-     * @param display     die anstelle der Auswahl-Objekte angezeigten Objekte
-     *                    (kann <code>null</code> sein)
-     * @exception IllegalArgumentException falls sich die Array-Groessen von
-     *            <code>value</code> und <code>display</code> unterscheiden
-     */
-    public Combo(String label, boolean inputNeeded, E[] value, E defValue, Object[] display) {
-      super(label,inputNeeded,value,defValue,display);
-    }
-
-    /**
-     * Erzeugt eine neue Auswahl-Option.
-     * @param label       Beschreibung
-     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
-     * @param value       die zur Auswahl stehenden Objekte
-     * @param defValue    vorgeblendetes Auswahlobjekt
-     * @param display     die anstelle der Auswahl-Objekte angezeigten Objekte
-     *                    (kann <code>null</code> sein)
-     * @param tooltip     die fuer jedes Auswahl-Objekt angezeigten Tooltips
-     *                    (kann <code>null</code> sein)
-     * @exception IllegalArgumentException falls sich die Array-Groessen von
-     *            <code>value</code> und <code>display</code> unterscheiden
-     */
-    public Combo(String label, boolean inputNeeded, E[] value, E defValue, Object[] display, Map<Object,String> tooltip) {
-      super(label,inputNeeded,value,defValue,display,tooltip);
-    }
-
-    /**
-     * Erzeugt eine neue Auswahl-Option. Es wird das erste Auswahl-Objekt
-     * vorgeblendet.
-     * @param label       Beschreibung
-     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
-     * @param value       die zur Auswahl stehenden Objekte
-     * @param display     die anstelle der Auswahl-Objekte angezeigten Objekte
-     *                    (kann <code>null</code> sein)
-     * @exception IllegalArgumentException falls sich die Array-Groessen von
-     *            <code>value</code> und <code>display</code> unterscheiden
-     */
-    public Combo(String label, boolean inputNeeded, E[] value, Object[] display) {
-      super(label,inputNeeded,value,display);
-    }
-
-    /**
-     * Erzeugt eine leere Auswahl-Option. Diese muss nachtraeglich ueber
-     * {@link #setSelectionObjects(Object[],Object[])} befuellt werden.
-     * @param label       Beschreibung
-     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
-     */
-    public Combo(String label, boolean inputNeeded) {
-      super(label,inputNeeded,new Object[0],new Object[0]);
-    }
-
-    /**
-     * Erzeugt eine neue Instanz von {@link JComboBox}.
-     */
-    protected JComboBox createInputComponent() {
-      JComboBox comboBox = new JComboBox();
-      // Change Listener
-      comboBox.addItemListener( new ItemListener() {
-        Object oldValue = null;
-        public void itemStateChanged(ItemEvent e) {
-          if ( e.getStateChange() == e.SELECTED ) {
-            Object newValue = getValue();
-            if ( oldValue != newValue )
-              fireOptionChanged(oldValue,newValue);
-            oldValue = newValue;
-          }
-        }
-      });
-      return comboBox;
-    }
-
-    /**
-     * Befuellt die ComboBox-Liste neu.
-     */
-    protected void performSelectionUpdate() {
-      // wenn eine Leereingabe erlaubt ist, wird am Anfang ein
-      // null-Eintrag eingefuegt
-      if ( !inputNeeded() ) {
-        Object[] newSelObj = new Object[this.selectionObject.length+1];
-        Object[] newDisObj = new Object[this.displayObject.length+1];
-
-        newSelObj[0] = null;
-        newDisObj[0] = null;
-        for (int i=0; i<this.selectionObject.length; i++) {
-          newSelObj[i+1] = this.selectionObject[i];
-          newDisObj[i+1] = this.displayObject[i];
-        }
-        this.selectionObject = newSelObj;
-        this.displayObject   = newDisObj;
-      }
-      // Combo-Box aktualisieren
-      ((JComboBox)inpComp).removeAllItems();
-      for (int i=0; i<displayObject.length; i++)
-        ((JComboBox)inpComp).addItem( displayObject[i] );
-      // Tooltips neu setzen
-      ((JComboBox)inpComp).setRenderer( new ToolTipComboBoxRenderer(displayToolTip) );
-    }
-
-    /**
-     * Liefert den Index, der in der ComboBox-Liste ausgewaehlt wurde.
-     * @return <code>-1</code> falls kein Objekt ausgewaehlt wurde
-     */
-    public int getSelectedIndex() {
-      return ((JComboBox)inpComp).getSelectedIndex();
-    }
-
-    /**
-     * Setzt den Index, der in der ComboBox-Liste ausgewaehlt wurde.
-     * @param idx Listen-Index (-1 um eine Leer-Auswahl zu erzeugen)
-     */
-    public void setSelectedIndex(int idx) {
-      Object oldValue = getValue();
-      ((JComboBox)inpComp).setSelectedIndex(idx);
-      Object newValue = getValue();
-      if ( oldValue != newValue || oldValue!=null && !oldValue.equals( getValue() ) )
-        fireOptionChanged(oldValue,newValue);
-    }
-  }
-
-  /**
-   * Diese Klasse stellt eine Auswahl-Option dar, die durch ein {@link JPanel}
-   * mit vertikal angeordneten {@link JRadioButton JRadioButtons} dargestellt wird.
-   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-   * @version 1.0
-   */
-  public static class Radio<E> extends SelectionInputOption {
-    /** Gruppe, in der die RadioButton agieren. */
-    protected ButtonGroup buttonGroup;
-    /** Speichert die letzte Auswahl. */
-    protected Object lastSelection = null;
-    /** Liste der Buttons. */
-    protected Vector<JRadioButton> buttonList;
-
-    /** ActionListener, der auf die Button-Klicks reagiert und ggf. Events
-     *  feuert. */
-    private ActionListener actionListener = new ActionListener() {
-      public void actionPerformed(ActionEvent e) {
-        Object newValue = getValue();
-        if ( lastSelection != newValue )
-          fireOptionChanged(lastSelection,newValue);
-        lastSelection = newValue;
-      }
-    };
-
-    /**
-     * Erzeugt eine neue Auswahl-Option.
-     * @param label       Beschreibung
-     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
-     * @param value       die zur Auswahl stehenden Objekte
-     * @param defIdx      Index der vorgeblendeten Auswahl
-     * @param display     die anstelle der Auswahl-Objekte angezeigten Objekte
-     *                    (kann <code>null</code> sein)
-     * @exception IllegalArgumentException falls sich die Array-Groessen von
-     *            <code>value</code> und <code>display</code> unterscheiden
-     */
-    public Radio(String label, boolean inputNeeded, E[] value, int defIdx, Object[] display) {
-      super(label,inputNeeded,value,defIdx, display);
-    }
-
-    /**
-     * Erzeugt eine neue Auswahl-Option.
-     * @param label       Beschreibung
-     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
-     * @param value       die zur Auswahl stehenden Objekte
-     * @param defValue    vorgeblendetes Auswahlobjekt
-     * @param display     die anstelle der Auswahl-Objekte angezeigten Objekte
-     *                    (kann <code>null</code> sein)
-     * @exception IllegalArgumentException falls sich die Array-Groessen von
-     *            <code>value</code> und <code>display</code> unterscheiden
-     */
-    public Radio(String label, boolean inputNeeded, E[] value, E defValue, Object[] display) {
-      super(label,inputNeeded,value,defValue,display);
-    }
-
-    /**
-     * Erzeugt eine neue Auswahl-Option.
-     * @param label       Beschreibung
-     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
-     * @param value       die zur Auswahl stehenden Objekte
-     * @param defValue    vorgeblendetes Auswahlobjekt
-     * @param display     die anstelle der Auswahl-Objekte angezeigten Objekte
-     *                    (kann <code>null</code> sein)
-     * @param tooltip     die fuer jedes Auswahl-Objekt angezeigten Tooltips
-     *                    (kann <code>null</code> sein)
-     * @exception IllegalArgumentException falls sich die Array-Groessen von
-     *            <code>value</code> und <code>display</code> unterscheiden
-     */
-    public Radio(String label, boolean inputNeeded, E[] value, E defValue, Object[] display, Map<Object,String> tooltip) {
-      super(label,inputNeeded,value,defValue,display,tooltip);
-    }
-
-    /**
-     * Erzeugt eine neue Auswahl-Option. Es wird das erste Auswahl-Objekt
-     * vorgeblendet.
-     * @param label       Beschreibung
-     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
-     * @param value       die zur Auswahl stehenden Objekte
-     * @param display     die anstelle der Auswahl-Objekte angezeigten Objekte
-     *                    (kann <code>null</code> sein)
-     * @exception IllegalArgumentException falls sich die Array-Groessen von
-     *            <code>value</code> und <code>display</code> unterscheiden
-     */
-    public Radio(String label, boolean inputNeeded, E[] value, Object[] display) {
-      super(label,inputNeeded,value,display);
-    }
-
-    /**
-     * Erzeugt eine leere Auswahl-Option. Diese muss nachtraeglich ueber
-     * {@link #setSelectionObjects(Object[],Object[])} befuellt werden.
-     * @param label       Beschreibung
-     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
-     */
-    public Radio(String label, boolean inputNeeded) {
-      super(label,inputNeeded,new Object[0],new Object[0]);
-    }
-
-    /**
-     * Erzeugt eine neues {@link JPanel}, in dem untereinander
-     * {@link JRadioButton JRadioButtons} fuer jede Auswahl-Option
-     * angeordnet werden.
-     */
-    protected JPanel createInputComponent() {
-      this.buttonGroup = new ButtonGroup();
-      this.buttonList  = new Vector<JRadioButton>();
-      JPanel panel = new JPanel();
-      panel.setLayout( new BoxLayout(panel,BoxLayout.Y_AXIS) );
-      return panel;
-    }
-
-    /**
-     * Befuellt das Panel neu mit RadioButtons.
-     */
-    protected void performSelectionUpdate() {
-      JPanel buttonPanel = ((JPanel)inpComp);
-      // Panel aktualisieren
-      buttonGroup = new ButtonGroup();
-      buttonPanel.removeAll();
-      if ( buttonList != null )
-        buttonList.clear();
-      for (int i=0; i<displayObject.length; i++) {
-        Object disObj = displayObject[i];
-        JRadioButton button = null;
-        if ( disObj instanceof Icon )
-          button = new JRadioButton((Icon)disObj);
-        else
-          button = new JRadioButton(disObj.toString());
-        button.addActionListener(actionListener);
-        if (this.displayToolTip != null)
-          button.setToolTipText( (String)displayToolTip.get(selectionObject[i]) );
-        buttonPanel.add(button);
-        buttonGroup.add(button);
-        buttonList.add(button);
-      }
-    }
-
-    /**
-     * Liefert den Index, der in der Button-Liste ausgewaehlt wurde.
-     * @return <code>-1</code> falls kein Objekt ausgewaehlt wurde
-     */
-    public int getSelectedIndex() {
-      if ( buttonGroup.getSelection() == null )
-        return -1;
-      return buttonList.indexOf( buttonGroup.getSelectedButton() );
-    }
-
-    /**
-     * Setzt den Index, der in der Button-Liste ausgewaehlt wurde.
-     * @param idx Listen-Index (-1 um eine Leer-Auswahl zu erzeugen)
-     */
-    public void setSelectedIndex(int idx) {
-// Event wird - glaube ich - bereits durch den ActionListener
-// des RadioButtons realisiert!
-//      Object oldValue = getValue();
-      if ( idx == -1 || idx >= buttonList.size() )
-        buttonGroup.setUnselected();
-      else
-        buttonList.elementAt(idx).setSelected(true);
-//      Object newValue = getValue();
-//      if ( oldValue != newValue || oldValue!=null && !oldValue.equals( getValue() ) )
-//        fireOptionChanged(oldValue,newValue);
-    }
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
+
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Vector;
+
+import javax.swing.BoxLayout;
+import javax.swing.Icon;
+import javax.swing.JComboBox;
+import javax.swing.JList;
+import javax.swing.JRadioButton;
+import javax.swing.plaf.basic.BasicComboBoxRenderer;
+
+/**
+ * Diese Klasse stellt eine Auswahl-Eingabe-Option fuer das {@link MultipleOptionPane}
+ * dar. Die Klasse kann nicht direkt instanziiert werden.
+ * Statt dessen sind die eingebetteten Klassen
+ * <ul>
+ * <li>{@link SelectionInputOption.Combo SelectionInputOption.Combo}</li>
+ * </ul>
+ * zu verwenden.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public abstract class SelectionInputOption<E> extends InputOption<E> {
+  /** Speichert die Objekte, die zur Auswahl stehen. */
+  protected E[] selectionObject = null;
+  /** Speichert die Objekte, die fuer die Auswahl angezeigt werden. */
+  protected Object[] displayObject   = null;
+  /** Speichert fuer jedes {@link #selectionObject} einen ToolTip, der
+   *  fuer das Auswahl-Objekt angezeigt wird. */
+  protected Map<Object,String> displayToolTip  = new HashMap<Object, String>();
+
+  /**
+   * Erzeugt eine neue Eingabe-Option.
+   * @param label       Beschreibung
+   * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
+   * @param value       die zur Auswahl stehenden Objekte
+   * @param defIdx      Index der vorgeblendeten Auswahl
+   * @param display     die anstelle der Auswahl-Objekte angezeigten Objekte
+   *                    (kann <code>null</code> sein)
+   * @exception IllegalArgumentException falls sich die Array-Groessen von
+   *            <code>value</code> und <code>display</code> unterscheiden
+   */
+  protected SelectionInputOption(String label, boolean inputNeeded, E[] value, int defIdx, Object[] display) {
+    super(label,inputNeeded);
+    // Referenz auf Objekte merken und Komponente befuellen
+    setSelectionObjects(value,display);
+    setSelectedIndex(defIdx);
+  }
+
+  /**
+   * Erzeugt eine neue Eingabe-Option.
+   * @param label       Beschreibung
+   * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
+   * @param value       die zur Auswahl stehenden Objekte
+   * @param defValue    vorgeblendetes Auswahlobjekt
+   * @param display     die anstelle der Auswahl-Objekte angezeigten Objekte
+   *                    (kann <code>null</code> sein)
+   * @exception IllegalArgumentException falls sich die Array-Groessen von
+   *            <code>value</code> und <code>display</code> unterscheiden
+   */
+  protected SelectionInputOption(String label, boolean inputNeeded, E[] value, E defValue, Object[] display) {
+    this(label,inputNeeded,value,defValue,display,null);
+  }
+
+  /**
+   * Erzeugt eine neue Eingabe-Option.
+   * @param label       Beschreibung
+   * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
+   * @param value       die zur Auswahl stehenden Objekte
+   * @param defValue    vorgeblendetes Auswahlobjekt
+   * @param display     die anstelle der Auswahl-Objekte angezeigten Objekte
+   *                    (kann <code>null</code> sein)
+   * @param tooltip     die fuer jedes Auswahl-Objekt angezeigten Tooltips
+   *                    (kann <code>null</code> sein)
+   * @exception IllegalArgumentException falls sich die Array-Groessen von
+   *            <code>value</code> und <code>display</code> unterscheiden
+   */
+  protected SelectionInputOption(String label, boolean inputNeeded, E[] value, E defValue, Object[] display, Map<Object,String> tooltip) {
+    super(label,inputNeeded);
+    // Referenz auf Objekte merken und Komponente befuellen
+    setSelectionObjects(value,display,tooltip);
+    setSelectedItem(defValue);
+  }
+
+  /**
+   * Erzeugt eine neue Eingabe-Option. Es wird (sofern vorhanden) das erste
+   * Auswahl-Objekt vorgeblendet.
+   * @param label       Beschreibung
+   * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
+   * @param value       die zur Auswahl stehenden Objekte
+   * @param display     die anstelle der Auswahl-Objekte angezeigten Objekte
+   *                    (kann <code>null</code> sein)
+   * @exception IllegalArgumentException falls sich die Array-Groessen von
+   *            <code>value</code> und <code>display</code> unterscheiden
+   */
+  protected SelectionInputOption(String label, boolean inputNeeded, E[] value, Object[] display) {
+    this(label,inputNeeded,value,value.length > 0 ? 0 : -1, display);
+  }
+
+  /**
+   * Setzt die im Auswahlfeld zur Verfuegung stehenden Eintraege
+   * @param value       die zur Auswahl stehenden Objekte
+   * @param display     die anstelle der Auswahl-Objekte angezeigten Objekte
+   *                    (kann <code>null</code> sein)
+   * @exception IllegalArgumentException falls sich die Array-Groessen von
+   *            <code>value</code> und <code>display</code> unterscheiden
+   *
+   */
+  public void setSelectionObjects(E[] value, Object[] display) {
+    setSelectionObjects(value,display,null);
+  }
+  
+  /**
+   * Setzt die im Auswahlfeld zur Verfuegung stehenden Eintraege
+   * @param value       die zur Auswahl stehenden Objekte
+   * @param display     die anstelle der Auswahl-Objekte angezeigten Objekte
+   *                    (kann <code>null</code> sein)
+   * @param tooltip     die fuer jedes Auswahl-Objekt angezeigten Tooltips
+   *                    (kann <code>null</code> sein)
+   * @exception IllegalArgumentException falls sich die Array-Groessen von
+   *            <code>value</code> und <code>display</code> unterscheiden
+   *
+   */
+  public void setSelectionObjects(E[] value, Object[] display, Map<Object,String> tooltip) {
+    // werden keine Wert angegeben, wird dies wie eine leere
+    // Menge behandelt
+    if (value == null)
+      value = (E[])new Object[0];
+    // Wurden keine speziellen Anzeigewerte angegeben, werden die
+    // Auswahl-Objekte verwendet
+    if (display == null)
+      display = value;
+    // Haben der Auswahl- und der Anzeige-Array unterschiedliche
+    // Laenge, wird dies nicht akzeptiert
+    if ( ( (Object[]) display).length != ( (E[]) value).length)
+      throw new IllegalArgumentException("display-Array and value-Array must have the same size!");
+
+    Object lastSelection = getValue();
+    this.selectionObject = value;
+    this.displayObject   = display;
+    this.displayToolTip  = tooltip;
+    performSelectionUpdate();
+    setSelectedItem(lastSelection);
+  }
+
+  /**
+   * Aktualisiert die Objekte in der der Auswahlkomponente. Wird aufgerufen,
+   * wenn dich die zur Auswahl stehenden Objekte aendern. Die Variablen
+   * {@link #selectionObject} und {@link #displayObject} sind dann bereits
+   * aktualisiert,
+   */
+  protected abstract void performSelectionUpdate();
+
+  /**
+   * Liefert immer <code>true</code>, da keine speziellen Anforderungen
+   * an die Auswahl-Eingabe gestellt werden.
+   */
+  protected boolean performIsInputValid() {
+    return true;
+  }
+
+  /**
+   * Prueft, ob im Auswahlfeld ein Eintrag ausgewaehlt wurde.
+   */
+  protected boolean performIsInputEmpty() {
+    return getSelectedIndex() < 0;
+  }
+
+  /**
+   * Liefert das Objekt, das zum aktuell ausgewaehlten Eintrag der
+   * Auswahl-Liste gehoert.
+   * @return <code>null</code> falls kein Objekt ausgewaehlt ist
+   */
+  protected E performGetValue() {
+    int idx = getSelectedIndex();
+    return idx < 0 ? null : selectionObject[getSelectedIndex()];
+  }
+
+  /**
+   * Setzt das Objekt, das in der Auswahlliste angewaehlt wird. Ruft
+   * {@link #setSelectedItem(Object)} auf.
+   * @return immer <code>true</code>
+   */
+  protected boolean performSetValue(E newValue) {
+    setSelectedItem(newValue);
+    return true;
+  }
+
+  /**
+   * Setzt einen neuen Wert, mit der die Eingabe-Option belegt wird.
+   * Ruft lediglich {@link #performSetValue(Object)} auf. Ueberschreibt die
+   * Methode von {@link InputOption}, da die Ueberpruefung auf Aenderung
+   * (und Event-Ausloesung) in {@link #setSelectedIndex(int)} erfolgt.
+   * @param newValue neuer Wert
+   * @return <code>false</code> gdw. der Objekt-Typ fuer die Option nicht
+   *         zulaessig ist
+   */
+  public boolean setValue(E newValue) {
+    if ( !performSetValue(newValue) )
+      return false;
+    return true;
+  }
+
+  /**
+   * Liefert den Index, der in der Objekt-Liste ausgewaehlt wurde.
+   * @return <code>-1</code> falls kein Objekt ausgewaehlt wurde
+   */
+  public abstract int getSelectedIndex();
+
+  /**
+   * Setzt den Index, der in der Objekt-Liste ausgewaehlt wurde. <b>Da dies die
+   * Basis-Methode fuer alle Aenderungsoperationen darstellt, muss sie
+   * die Ueberpruefung auf Aenderung implementieren und ggf.
+   * {@link #fireOptionChanged(Object,Object)} ausloesen.</b>
+   * @param idx Listen-Index (-1 um eine Leer-Auswahl zu erzeugen)
+   */
+  public abstract void setSelectedIndex(int idx);
+
+  /**
+   * Setzt die Auswahl auf ein bestimmtes Objekt. Ist dieses nicht vorhanden,
+   * wird die Auswahlliste auf eine leere Auswahl eingestellt.
+   */
+  public void setSelectedItem(Object object) {
+    // altes Object in der neuen Objektliste suchen
+    int newIdx = -1;
+    for (int i=0; i<selectionObject.length && newIdx < 0; i++)
+//      if ( selectionObject[i] == object )
+      if ( selectionObject[i]==null && object==null ||
+           selectionObject[i]!=null && selectionObject[i].equals(object) )
+        newIdx = i;
+    setSelectedIndex(newIdx);
+  }
+
+  /**
+   * Liefert das Anzeige-Objekt der akuellen Auswahl.
+   */
+  public Object getSelectedDisplayItem() {
+    // altes Object in der neuen Objektliste suchen
+    if ( getSelectedIndex() >= 0 )
+      return displayObject[ getSelectedIndex() ];
+   return null;
+  }
+
+  /**
+   * Setzt die Auswahl auf ein bestimmtes Anzeige-Objekt. Ist dieses nicht vorhanden,
+   * wird die Auswahlliste auf eine leere Auswahl eingestellt.
+   */
+  public void setSelectedDisplayItem(Object object) {
+    // altes Object in der neuen Objektliste suchen
+    int newIdx = -1;
+    for (int i=0; i<displayObject.length && newIdx < 0; i++)
+//      if ( selectionObject[i] == object )
+      if ( displayObject[i]==null && object==null ||
+           displayObject[i]!=null && displayObject[i].equals(object) )
+        newIdx = i;
+    setSelectedIndex(newIdx);
+  }
+
+  /**
+   * Liefert die Anzahl der zur Auswahl stehenden Eintraege.
+   */
+  public int getSelectedItemCount() {
+    return selectionObject != null ? selectionObject.length : 0;
+  }
+
+  /**
+   * Diese Klasse stellt eine Auswahl-Option dar, die durch eine
+   * {@link JComboBox} dargestellt wird.
+   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+   * @version 1.0
+   */
+  public static class Combo<E> extends SelectionInputOption {
+    /**
+     * Erzeugt eine neue Auswahl-Option.
+     * @param label       Beschreibung
+     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
+     * @param value       die zur Auswahl stehenden Objekte
+     * @param defIdx      Index der vorgeblendeten Auswahl
+     * @param display     die anstelle der Auswahl-Objekte angezeigten Objekte
+     *                    (kann <code>null</code> sein)
+     * @exception IllegalArgumentException falls sich die Array-Groessen von
+     *            <code>value</code> und <code>display</code> unterscheiden
+     */
+    public Combo(String label, boolean inputNeeded, E[] value, int defIdx, Object[] display) {
+      super(label,inputNeeded,value,defIdx, display);
+    }
+
+    /**
+     * Erzeugt eine neue Auswahl-Option.
+     * @param label       Beschreibung
+     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
+     * @param value       die zur Auswahl stehenden Objekte
+     * @param defValue    vorgeblendetes Auswahlobjekt
+     * @param display     die anstelle der Auswahl-Objekte angezeigten Objekte
+     *                    (kann <code>null</code> sein)
+     * @exception IllegalArgumentException falls sich die Array-Groessen von
+     *            <code>value</code> und <code>display</code> unterscheiden
+     */
+    public Combo(String label, boolean inputNeeded, E[] value, E defValue, Object[] display) {
+      super(label,inputNeeded,value,defValue,display);
+    }
+
+    /**
+     * Erzeugt eine neue Auswahl-Option.
+     * @param label       Beschreibung
+     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
+     * @param value       die zur Auswahl stehenden Objekte
+     * @param defValue    vorgeblendetes Auswahlobjekt
+     * @param display     die anstelle der Auswahl-Objekte angezeigten Objekte
+     *                    (kann <code>null</code> sein)
+     * @param tooltip     die fuer jedes Auswahl-Objekt angezeigten Tooltips
+     *                    (kann <code>null</code> sein)
+     * @exception IllegalArgumentException falls sich die Array-Groessen von
+     *            <code>value</code> und <code>display</code> unterscheiden
+     */
+    public Combo(String label, boolean inputNeeded, E[] value, E defValue, Object[] display, Map<Object,String> tooltip) {
+      super(label,inputNeeded,value,defValue,display,tooltip);
+    }
+
+    /**
+     * Erzeugt eine neue Auswahl-Option. Es wird das erste Auswahl-Objekt
+     * vorgeblendet.
+     * @param label       Beschreibung
+     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
+     * @param value       die zur Auswahl stehenden Objekte
+     * @param display     die anstelle der Auswahl-Objekte angezeigten Objekte
+     *                    (kann <code>null</code> sein)
+     * @exception IllegalArgumentException falls sich die Array-Groessen von
+     *            <code>value</code> und <code>display</code> unterscheiden
+     */
+    public Combo(String label, boolean inputNeeded, E[] value, Object[] display) {
+      super(label,inputNeeded,value,display);
+    }
+
+    /**
+     * Erzeugt eine leere Auswahl-Option. Diese muss nachtraeglich ueber
+     * {@link #setSelectionObjects(Object[],Object[])} befuellt werden.
+     * @param label       Beschreibung
+     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
+     */
+    public Combo(String label, boolean inputNeeded) {
+      super(label,inputNeeded,new Object[0],new Object[0]);
+    }
+
+    /**
+     * Erzeugt eine neue Instanz von {@link JComboBox}.
+     */
+    protected JComboBox createInputComponent() {
+      JComboBox comboBox = new JComboBox();
+      // Change Listener
+      comboBox.addItemListener( new ItemListener() {
+        Object oldValue = null;
+        public void itemStateChanged(ItemEvent e) {
+          if ( e.getStateChange() == e.SELECTED ) {
+            Object newValue = getValue();
+            if ( oldValue != newValue )
+              fireOptionChanged(oldValue,newValue);
+            oldValue = newValue;
+          }
+        }
+      });
+      return comboBox;
+    }
+
+    /**
+     * Befuellt die ComboBox-Liste neu.
+     */
+    protected void performSelectionUpdate() {
+      // wenn eine Leereingabe erlaubt ist, wird am Anfang ein
+      // null-Eintrag eingefuegt
+      if ( !inputNeeded() ) {
+        Object[] newSelObj = new Object[this.selectionObject.length+1];
+        Object[] newDisObj = new Object[this.displayObject.length+1];
+
+        newSelObj[0] = null;
+        newDisObj[0] = null;
+        for (int i=0; i<this.selectionObject.length; i++) {
+          newSelObj[i+1] = this.selectionObject[i];
+          newDisObj[i+1] = this.displayObject[i];
+        }
+        this.selectionObject = newSelObj;
+        this.displayObject   = newDisObj;
+      }
+      // Combo-Box aktualisieren
+      ((JComboBox)inpComp).removeAllItems();
+      for (int i=0; i<displayObject.length; i++)
+        ((JComboBox)inpComp).addItem( displayObject[i] );
+      // Tooltips neu setzen
+      ((JComboBox)inpComp).setRenderer( new ToolTipComboBoxRenderer(displayToolTip) );
+    }
+
+    /**
+     * Liefert den Index, der in der ComboBox-Liste ausgewaehlt wurde.
+     * @return <code>-1</code> falls kein Objekt ausgewaehlt wurde
+     */
+    public int getSelectedIndex() {
+      return ((JComboBox)inpComp).getSelectedIndex();
+    }
+
+    /**
+     * Setzt den Index, der in der ComboBox-Liste ausgewaehlt wurde.
+     * @param idx Listen-Index (-1 um eine Leer-Auswahl zu erzeugen)
+     */
+    public void setSelectedIndex(int idx) {
+      Object oldValue = getValue();
+      ((JComboBox)inpComp).setSelectedIndex(idx);
+      Object newValue = getValue();
+      if ( oldValue != newValue || oldValue!=null && !oldValue.equals( getValue() ) )
+        fireOptionChanged(oldValue,newValue);
+    }
+  }
+
+  /**
+   * Diese Klasse stellt eine Auswahl-Option dar, die durch ein {@link JPanel}
+   * mit vertikal angeordneten {@link JRadioButton JRadioButtons} dargestellt wird.
+   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+   * @version 1.0
+   */
+  public static class Radio<E> extends SelectionInputOption {
+    /** Gruppe, in der die RadioButton agieren. */
+    protected ButtonGroup buttonGroup;
+    /** Speichert die letzte Auswahl. */
+    protected Object lastSelection = null;
+    /** Liste der Buttons. */
+    protected Vector<JRadioButton> buttonList;
+
+    /** ActionListener, der auf die Button-Klicks reagiert und ggf. Events
+     *  feuert. */
+    private ActionListener actionListener = new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        Object newValue = getValue();
+        if ( lastSelection != newValue )
+          fireOptionChanged(lastSelection,newValue);
+        lastSelection = newValue;
+      }
+    };
+
+    /**
+     * Erzeugt eine neue Auswahl-Option.
+     * @param label       Beschreibung
+     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
+     * @param value       die zur Auswahl stehenden Objekte
+     * @param defIdx      Index der vorgeblendeten Auswahl
+     * @param display     die anstelle der Auswahl-Objekte angezeigten Objekte
+     *                    (kann <code>null</code> sein)
+     * @exception IllegalArgumentException falls sich die Array-Groessen von
+     *            <code>value</code> und <code>display</code> unterscheiden
+     */
+    public Radio(String label, boolean inputNeeded, E[] value, int defIdx, Object[] display) {
+      super(label,inputNeeded,value,defIdx, display);
+    }
+
+    /**
+     * Erzeugt eine neue Auswahl-Option.
+     * @param label       Beschreibung
+     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
+     * @param value       die zur Auswahl stehenden Objekte
+     * @param defValue    vorgeblendetes Auswahlobjekt
+     * @param display     die anstelle der Auswahl-Objekte angezeigten Objekte
+     *                    (kann <code>null</code> sein)
+     * @exception IllegalArgumentException falls sich die Array-Groessen von
+     *            <code>value</code> und <code>display</code> unterscheiden
+     */
+    public Radio(String label, boolean inputNeeded, E[] value, E defValue, Object[] display) {
+      super(label,inputNeeded,value,defValue,display);
+    }
+
+    /**
+     * Erzeugt eine neue Auswahl-Option.
+     * @param label       Beschreibung
+     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
+     * @param value       die zur Auswahl stehenden Objekte
+     * @param defValue    vorgeblendetes Auswahlobjekt
+     * @param display     die anstelle der Auswahl-Objekte angezeigten Objekte
+     *                    (kann <code>null</code> sein)
+     * @param tooltip     die fuer jedes Auswahl-Objekt angezeigten Tooltips
+     *                    (kann <code>null</code> sein)
+     * @exception IllegalArgumentException falls sich die Array-Groessen von
+     *            <code>value</code> und <code>display</code> unterscheiden
+     */
+    public Radio(String label, boolean inputNeeded, E[] value, E defValue, Object[] display, Map<Object,String> tooltip) {
+      super(label,inputNeeded,value,defValue,display,tooltip);
+    }
+
+    /**
+     * Erzeugt eine neue Auswahl-Option. Es wird das erste Auswahl-Objekt
+     * vorgeblendet.
+     * @param label       Beschreibung
+     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
+     * @param value       die zur Auswahl stehenden Objekte
+     * @param display     die anstelle der Auswahl-Objekte angezeigten Objekte
+     *                    (kann <code>null</code> sein)
+     * @exception IllegalArgumentException falls sich die Array-Groessen von
+     *            <code>value</code> und <code>display</code> unterscheiden
+     */
+    public Radio(String label, boolean inputNeeded, E[] value, Object[] display) {
+      super(label,inputNeeded,value,display);
+    }
+
+    /**
+     * Erzeugt eine leere Auswahl-Option. Diese muss nachtraeglich ueber
+     * {@link #setSelectionObjects(Object[],Object[])} befuellt werden.
+     * @param label       Beschreibung
+     * @param inputNeeded gibt an, ob eine Eingabe erforderlich ist
+     */
+    public Radio(String label, boolean inputNeeded) {
+      super(label,inputNeeded,new Object[0],new Object[0]);
+    }
+
+    /**
+     * Erzeugt eine neues {@link JPanel}, in dem untereinander
+     * {@link JRadioButton JRadioButtons} fuer jede Auswahl-Option
+     * angeordnet werden.
+     */
+    protected JPanel createInputComponent() {
+      this.buttonGroup = new ButtonGroup();
+      this.buttonList  = new Vector<JRadioButton>();
+      JPanel panel = new JPanel();
+      panel.setLayout( new BoxLayout(panel,BoxLayout.Y_AXIS) );
+      return panel;
+    }
+
+    /**
+     * Befuellt das Panel neu mit RadioButtons.
+     */
+    protected void performSelectionUpdate() {
+      JPanel buttonPanel = ((JPanel)inpComp);
+      // Panel aktualisieren
+      buttonGroup = new ButtonGroup();
+      buttonPanel.removeAll();
+      if ( buttonList != null )
+        buttonList.clear();
+      for (int i=0; i<displayObject.length; i++) {
+        Object disObj = displayObject[i];
+        JRadioButton button = null;
+        if ( disObj instanceof Icon )
+          button = new JRadioButton((Icon)disObj);
+        else
+          button = new JRadioButton(disObj.toString());
+        button.addActionListener(actionListener);
+        if (this.displayToolTip != null)
+          button.setToolTipText( (String)displayToolTip.get(selectionObject[i]) );
+        buttonPanel.add(button);
+        buttonGroup.add(button);
+        buttonList.add(button);
+      }
+    }
+
+    /**
+     * Liefert den Index, der in der Button-Liste ausgewaehlt wurde.
+     * @return <code>-1</code> falls kein Objekt ausgewaehlt wurde
+     */
+    public int getSelectedIndex() {
+      if ( buttonGroup.getSelection() == null )
+        return -1;
+      return buttonList.indexOf( buttonGroup.getSelectedButton() );
+    }
+
+    /**
+     * Setzt den Index, der in der Button-Liste ausgewaehlt wurde.
+     * @param idx Listen-Index (-1 um eine Leer-Auswahl zu erzeugen)
+     */
+    public void setSelectedIndex(int idx) {
+// Event wird - glaube ich - bereits durch den ActionListener
+// des RadioButtons realisiert!
+//      Object oldValue = getValue();
+      if ( idx == -1 || idx >= buttonList.size() )
+        buttonGroup.setUnselected();
+      else
+        buttonList.elementAt(idx).setSelected(true);
+//      Object newValue = getValue();
+//      if ( oldValue != newValue || oldValue!=null && !oldValue.equals( getValue() ) )
+//        fireOptionChanged(oldValue,newValue);
+    }
+  }
+}

Modified: trunk/src/schmitzm/swing/SelectionPreservingCaret.java
===================================================================
--- trunk/src/schmitzm/swing/SelectionPreservingCaret.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/SelectionPreservingCaret.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,109 +1,138 @@
-package schmitzm.swing;
-
-import java.awt.event.FocusEvent;
-
-import javax.swing.UIManager;
-import javax.swing.text.DefaultCaret;
-
-/**
- * Caret implementation that doesn't blow away the selection when
- * we lose focus.
- * <br><br>
- * <b>Code taken from <a href="http://javatechniques.com/blog/fixing-disappearing-text-selections-when-a-menu-is-opened/">
- * javatechniques.com</a> and extended with the preserve-caret functionality.</b>
- */
-public class SelectionPreservingCaret extends DefaultCaret {
-    /**
-     * Flag, whether the caret is preserved, too.
-     */
-    private boolean preserveCaret = false;
-
-    /**
-     * The last SelectionPreservingCaret that lost focus
-     */
-    private static SelectionPreservingCaret last = null;
-
-    /**
-     * The last event that indicated loss of focus
-     */
-    private static FocusEvent lastFocusEvent = null;
-
-    /**
-     * Constructs a new caret which does preserve the selection.
-     * @param preserveCaret indicates whether the caret is also preserved
-     */
-    public SelectionPreservingCaret(boolean preserveCaret) {
-        this.preserveCaret = preserveCaret;
-
-        // The blink rate is set by BasicTextUI when the text component
-        // is created, and is not (re-) set when a new Caret is installed.
-        // This implementation attempts to pull a value from the UIManager,
-        // and defaults to a 500ms blink rate. This assumes that the
-        // look and feel uses the same blink rate for all text components
-        // (and hence we just pull the value for TextArea). If you are
-        // using a look and feel for which this is not the case, you may
-        // need to set the blink rate after creating the Caret.
-        int blinkRate = 500;
-        Object o = UIManager.get("TextArea.caretBlinkRate");
-        if ((o != null) && (o instanceof Integer)) {
-            Integer rate = (Integer) o;
-            blinkRate = rate.intValue();
-        }
-        setBlinkRate(blinkRate);
-    }
-
-    /**
-     * Constructs a new caret which does preserve the selection, but not the
-     * caret.
-     */
-    public SelectionPreservingCaret() {
-        this(false);
-    }
-
-    /**
-     * Called when the component containing the caret gains focus.
-     * DefaultCaret does most of the work, while the subclass checks
-     * to see if another instance of SelectionPreservingCaret previously
-     * had focus.
-     *
-     * @param evt the focus event
-     * @see java.awt.event.FocusListener#focusGained
-     */
-    public void focusGained(FocusEvent evt) {
-        super.focusGained(evt);
-
-        // If another instance of SelectionPreservingCaret had focus and
-        // we defered a focusLost event, deliver that event now.
-        if ((last != null) && (last != this)) {
-            last.hide();
-        }
-    }
-
-    /**
-     * Called when the component containing the caret loses focus. Instead
-     * of hiding both the caret and the selection, the subclass only
-     * hides the caret and saves a (static) reference to the event and this
-     * specific caret instance so that the event can be delivered later
-     * if appropriate.
-     *
-     * @param evt the focus event
-     * @see java.awt.event.FocusListener#focusLost
-     */
-    public void focusLost(FocusEvent evt) {
-        if ( !preserveCaret )
-          setVisible(false);
-        last = this;
-        lastFocusEvent = evt;
-    }
-
-    /**
-     * Delivers a defered focusLost event to this caret.
-     */
-    protected void hide() {
-        if (last == this) {
-            super.focusLost(lastFocusEvent);
-            last = null;
-            lastFocusEvent = null;
-        }
-    }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
+
+import java.awt.event.FocusEvent;
+
+import javax.swing.UIManager;
+import javax.swing.text.DefaultCaret;
+
+/**
+ * Caret implementation that doesn't blow away the selection when
+ * we lose focus.
+ * <br><br>
+ * <b>Code taken from <a href="http://javatechniques.com/blog/fixing-disappearing-text-selections-when-a-menu-is-opened/">
+ * javatechniques.com</a> and extended with the preserve-caret functionality.</b>
+ */
+public class SelectionPreservingCaret extends DefaultCaret {
+    /**
+     * Flag, whether the caret is preserved, too.
+     */
+    private boolean preserveCaret = false;
+
+    /**
+     * The last SelectionPreservingCaret that lost focus
+     */
+    private static SelectionPreservingCaret last = null;
+
+    /**
+     * The last event that indicated loss of focus
+     */
+    private static FocusEvent lastFocusEvent = null;
+
+    /**
+     * Constructs a new caret which does preserve the selection.
+     * @param preserveCaret indicates whether the caret is also preserved
+     */
+    public SelectionPreservingCaret(boolean preserveCaret) {
+        this.preserveCaret = preserveCaret;
+
+        // The blink rate is set by BasicTextUI when the text component
+        // is created, and is not (re-) set when a new Caret is installed.
+        // This implementation attempts to pull a value from the UIManager,
+        // and defaults to a 500ms blink rate. This assumes that the
+        // look and feel uses the same blink rate for all text components
+        // (and hence we just pull the value for TextArea). If you are
+        // using a look and feel for which this is not the case, you may
+        // need to set the blink rate after creating the Caret.
+        int blinkRate = 500;
+        Object o = UIManager.get("TextArea.caretBlinkRate");
+        if ((o != null) && (o instanceof Integer)) {
+            Integer rate = (Integer) o;
+            blinkRate = rate.intValue();
+        }
+        setBlinkRate(blinkRate);
+    }
+
+    /**
+     * Constructs a new caret which does preserve the selection, but not the
+     * caret.
+     */
+    public SelectionPreservingCaret() {
+        this(false);
+    }
+
+    /**
+     * Called when the component containing the caret gains focus.
+     * DefaultCaret does most of the work, while the subclass checks
+     * to see if another instance of SelectionPreservingCaret previously
+     * had focus.
+     *
+     * @param evt the focus event
+     * @see java.awt.event.FocusListener#focusGained
+     */
+    public void focusGained(FocusEvent evt) {
+        super.focusGained(evt);
+
+        // If another instance of SelectionPreservingCaret had focus and
+        // we defered a focusLost event, deliver that event now.
+        if ((last != null) && (last != this)) {
+            last.hide();
+        }
+    }
+
+    /**
+     * Called when the component containing the caret loses focus. Instead
+     * of hiding both the caret and the selection, the subclass only
+     * hides the caret and saves a (static) reference to the event and this
+     * specific caret instance so that the event can be delivered later
+     * if appropriate.
+     *
+     * @param evt the focus event
+     * @see java.awt.event.FocusListener#focusLost
+     */
+    public void focusLost(FocusEvent evt) {
+        if ( !preserveCaret )
+          setVisible(false);
+        last = this;
+        lastFocusEvent = evt;
+    }
+
+    /**
+     * Delivers a defered focusLost event to this caret.
+     */
+    protected void hide() {
+        if (last == this) {
+            super.focusLost(lastFocusEvent);
+            last = null;
+            lastFocusEvent = null;
+        }
+    }
+}

Modified: trunk/src/schmitzm/swing/SliderSpinnerPanel.java
===================================================================
--- trunk/src/schmitzm/swing/SliderSpinnerPanel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/SliderSpinnerPanel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,225 +1,243 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing;
-
-import java.awt.Font;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-
-import javax.swing.JLabel;
-import javax.swing.JSlider;
-import javax.swing.JSpinner;
-import javax.swing.SpinnerNumberModel;
-import javax.swing.event.ChangeEvent;
-import javax.swing.event.ChangeListener;
-
-/**
- * Dieses Panel enthaelt einen Slider, der mit einem Spinner verknuepft ist.
- * Zusaetzlich wird eine Ueberschrift ausgewiesen.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class SliderSpinnerPanel extends JPanel {
-  /** Konstante fuer die <b>horizontale</b> Orientierung des Sliders.
-   *  @see JSlider#HORIZONTAL */
-  public static final int HORIZONTAL = JSlider.HORIZONTAL;
-  /** Konstante fuer die <b>vertikale</b> Orientierung des Sliders.
-   *  @see JSlider#VERTICAL */
-  public static final int VERTICAL = JSlider.VERTICAL;
-
-  /** Slider des Panels. */
-  protected JSlider slider = null;
-  /** Ueberschrift-Label des Panels. */
-  protected JLabel headerLabel = null;
-  /** Spinner des Panels. */
-  protected JSpinner spinner = null;
-
-  /**
-   * Erzeugt ein neues Panel.
-   * @param orientation Orientierung des Sliders
-   * @param min Minimal einstellbarer Wert
-   * @param max Maximal einstellbarer Wert
-   * @param step Schrittweite fuer Spinner
-   * @param value Initialer Wert
-   * @param headerText Text fuer das Ueberschrift-Label (wenn {@code null} wird keine Ueberschrift ausgegeben!)
-   */
-  public SliderSpinnerPanel(int orientation, double min, double max, double step, double value, String headerText) {
-    super();
-    this.setLayout( new GridBagLayout() );
-    // Ueberschrift
-    if ( headerText != null ) {
-      this.headerLabel = new JLabel( headerText );
-      this.headerLabel.setFont( headerLabel.getFont().deriveFont(Font.BOLD) );
-      this.add( headerLabel, new GridBagConstraints(
-        0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.SOUTHWEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0) );
-    }
-    // Slider
-    this.slider = new JSlider(orientation);
-    this.add( slider, new GridBagConstraints(
-      0, 1, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0) );
-    // Spinner
-    this.spinner = new JSpinner();
-    SwingUtil.setPreferredWidth(this.spinner, 60);
-    this.add( spinner, new GridBagConstraints(
-      1, 1, 1, 1, 0.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0) );
-
-    // ActionListener auf Spinner, um Slider zu aktualisieren
-    this.spinner.addChangeListener(new ChangeListener() {
-      public void stateChanged(ChangeEvent e) {
-        double newValue = ((Number)spinner.getValue()).doubleValue();
-        if ( Math.round(newValue) != slider.getValue())
-          slider.setValue( (int)Math.round(newValue) );
-      }
-    });
-
-    // ActionListener auf Slider, um Spinner zu aktualisieren
-    this.slider.addChangeListener(new ChangeListener() {
-      public void stateChanged(ChangeEvent e) {
-        int newValue = slider.getValue();
-        if (newValue != Math.round( ((Number)spinner.getValue()).doubleValue() ))
-          spinner.setValue(newValue);
-      }
-    });
-
-    // Minimum, Maximum, StepSize und initalalier Wert einstellen
-    setRestrictions(value,min,max,step);
-  }
-
-  /**
-   * Erzeugt ein neues Panel. Minimum und Maximum werden automatisch auf 0 und
-   * 100 eingestellt.
-   * @param orientation Orientierung des Sliders
-   * @param headerText Text fuer das Ueberschrift-Label (wenn {@code null} wird keine Ueberschrift ausgegeben!)
-   */
-  public SliderSpinnerPanel(int orientation, String headerText) {
-    this(orientation, 0, 100, 1, 0, headerText);
-  }
-
-  /**
-   * Liefert den eingestellten Spinner-Wert.
-   */
-  public double getValue() {
-    return ((Number)spinner.getValue()).doubleValue();
-  }
-
-  /**
-   * Setzt den eingestellten Spinner-Wert.
-   * @param value Spinner-Wert
-   */
-  public void setValue(double value) {
-    spinner.setValue( Math.max( Math.min(value,getMaxValue()), getMinValue() ) );
-  }
-
-  /**
-   * Liefert den kleinsten einstellbaren Spinner-Wert.
-   */
-  public double getMinValue() {
-    return ((Number)((SpinnerNumberModel)spinner.getModel()).getMinimum()).doubleValue();
-  }
-
-  /**
-   * Setzt den kleinsten einstellbaren Spinner-Wert.
-   * @param min kleinster einstellbarer Spinner-Wert
-   */
-  public void setMinValue(double min) {
-    setRestrictions(
-      getValue(),
-      min,
-      getMaxValue(),
-      getStepSize()
-    );
-  }
-
-  /**
-   * Liefert den groessten einstellbaren Spinner-Wert.
-   */
-  public double getMaxValue() {
-    return ((Number)((SpinnerNumberModel)spinner.getModel()).getMaximum()).doubleValue();
-  }
-
-  /**
-   * Setzt den groessten einstellbaren Spinner-Wert.
-   * @param max groesster einstellbarer Spinner-Wert
-   */
-  public void setMaxValue(double max) {
-    setRestrictions(
-      getValue(),
-      getMinValue(),
-      max,
-      getStepSize()
-    );
-  }
-
-  /**
-   * Liefert die Schrittgroesse des Spinners.
-   */
-  public double getStepSize() {
-    return ((SpinnerNumberModel)spinner.getModel()).getStepSize().doubleValue();
-  }
-
-  /**
-   * Setzt die Schrittweiter des Spinners.
-   * @param stepSize groesster einstellbarer Spinner-Wert
-   */
-  public void setStepSize(double stepSize) {
-    setRestrictions(
-      getValue(),
-      getMinValue(),
-      getMaxValue(),
-      stepSize
-    );
-  }
-
-  /**
-   * Setzt alle Restriktionen des Sliders und Spinners neu.
-   * @param value    angezeigter Wert
-   * @param min      minimaler einstellbarer Wert
-   * @param max      maximaler einstellbarer Wert
-   * @param stepSize Schrittweite des Spinners
-   */
-  public void setRestrictions(double value, double min, double max, double stepSize) {
-    // Spinner einstellen
-    spinner.setModel( new SpinnerNumberModel(
-      value,
-      min,
-      max,
-      stepSize
-    ) );
-    spinner.setEditor( new JSpinner.NumberEditor(this.spinner,SwingUtil.getNumberFormatPattern(stepSize)) );
-    // Slider einstellen
-    slider.setMinimum( (int)Math.floor(min) );
-    slider.setMaximum( (int)Math.ceil(max) );
-    setValue( value );
-  }
-
-  /**
-   * Liefert den Slider des Panels.
-   */
-  public JSlider getSlider() {
-    return this.slider;
-  }
-
-  /**
-   * Liefert das Ueberschrift-Label des Panels.
-   */
-  public JLabel getHeaderLabel() {
-    return this.headerLabel;
-  }
-
-  /**
-   * Liefert den Spinner des Panels.
-   */
-  public JSpinner getSpinner() {
-    return this.spinner;
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
+
+import java.awt.Font;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+
+import javax.swing.JLabel;
+import javax.swing.JSlider;
+import javax.swing.JSpinner;
+import javax.swing.SpinnerNumberModel;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+
+/**
+ * Dieses Panel enthaelt einen Slider, der mit einem Spinner verknuepft ist.
+ * Zusaetzlich wird eine Ueberschrift ausgewiesen.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class SliderSpinnerPanel extends JPanel {
+  /** Konstante fuer die <b>horizontale</b> Orientierung des Sliders.
+   *  @see JSlider#HORIZONTAL */
+  public static final int HORIZONTAL = JSlider.HORIZONTAL;
+  /** Konstante fuer die <b>vertikale</b> Orientierung des Sliders.
+   *  @see JSlider#VERTICAL */
+  public static final int VERTICAL = JSlider.VERTICAL;
+
+  /** Slider des Panels. */
+  protected JSlider slider = null;
+  /** Ueberschrift-Label des Panels. */
+  protected JLabel headerLabel = null;
+  /** Spinner des Panels. */
+  protected JSpinner spinner = null;
+
+  /**
+   * Erzeugt ein neues Panel.
+   * @param orientation Orientierung des Sliders
+   * @param min Minimal einstellbarer Wert
+   * @param max Maximal einstellbarer Wert
+   * @param step Schrittweite fuer Spinner
+   * @param value Initialer Wert
+   * @param headerText Text fuer das Ueberschrift-Label (wenn {@code null} wird keine Ueberschrift ausgegeben!)
+   */
+  public SliderSpinnerPanel(int orientation, double min, double max, double step, double value, String headerText) {
+    super();
+    this.setLayout( new GridBagLayout() );
+    // Ueberschrift
+    if ( headerText != null ) {
+      this.headerLabel = new JLabel( headerText );
+      this.headerLabel.setFont( headerLabel.getFont().deriveFont(Font.BOLD) );
+      this.add( headerLabel, new GridBagConstraints(
+        0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.SOUTHWEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0) );
+    }
+    // Slider
+    this.slider = new JSlider(orientation);
+    this.add( slider, new GridBagConstraints(
+      0, 1, 1, 1, 1.0, 1.0, GridBagConstraints.CENTER, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0) );
+    // Spinner
+    this.spinner = new JSpinner();
+    SwingUtil.setPreferredWidth(this.spinner, 60);
+    this.add( spinner, new GridBagConstraints(
+      1, 1, 1, 1, 0.0, 0.0, GridBagConstraints.NORTHWEST, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0) );
+
+    // ActionListener auf Spinner, um Slider zu aktualisieren
+    this.spinner.addChangeListener(new ChangeListener() {
+      public void stateChanged(ChangeEvent e) {
+        double newValue = ((Number)spinner.getValue()).doubleValue();
+        if ( Math.round(newValue) != slider.getValue())
+          slider.setValue( (int)Math.round(newValue) );
+      }
+    });
+
+    // ActionListener auf Slider, um Spinner zu aktualisieren
+    this.slider.addChangeListener(new ChangeListener() {
+      public void stateChanged(ChangeEvent e) {
+        int newValue = slider.getValue();
+        if (newValue != Math.round( ((Number)spinner.getValue()).doubleValue() ))
+          spinner.setValue(newValue);
+      }
+    });
+
+    // Minimum, Maximum, StepSize und initalalier Wert einstellen
+    setRestrictions(value,min,max,step);
+  }
+
+  /**
+   * Erzeugt ein neues Panel. Minimum und Maximum werden automatisch auf 0 und
+   * 100 eingestellt.
+   * @param orientation Orientierung des Sliders
+   * @param headerText Text fuer das Ueberschrift-Label (wenn {@code null} wird keine Ueberschrift ausgegeben!)
+   */
+  public SliderSpinnerPanel(int orientation, String headerText) {
+    this(orientation, 0, 100, 1, 0, headerText);
+  }
+
+  /**
+   * Liefert den eingestellten Spinner-Wert.
+   */
+  public double getValue() {
+    return ((Number)spinner.getValue()).doubleValue();
+  }
+
+  /**
+   * Setzt den eingestellten Spinner-Wert.
+   * @param value Spinner-Wert
+   */
+  public void setValue(double value) {
+    spinner.setValue( Math.max( Math.min(value,getMaxValue()), getMinValue() ) );
+  }
+
+  /**
+   * Liefert den kleinsten einstellbaren Spinner-Wert.
+   */
+  public double getMinValue() {
+    return ((Number)((SpinnerNumberModel)spinner.getModel()).getMinimum()).doubleValue();
+  }
+
+  /**
+   * Setzt den kleinsten einstellbaren Spinner-Wert.
+   * @param min kleinster einstellbarer Spinner-Wert
+   */
+  public void setMinValue(double min) {
+    setRestrictions(
+      getValue(),
+      min,
+      getMaxValue(),
+      getStepSize()
+    );
+  }
+
+  /**
+   * Liefert den groessten einstellbaren Spinner-Wert.
+   */
+  public double getMaxValue() {
+    return ((Number)((SpinnerNumberModel)spinner.getModel()).getMaximum()).doubleValue();
+  }
+
+  /**
+   * Setzt den groessten einstellbaren Spinner-Wert.
+   * @param max groesster einstellbarer Spinner-Wert
+   */
+  public void setMaxValue(double max) {
+    setRestrictions(
+      getValue(),
+      getMinValue(),
+      max,
+      getStepSize()
+    );
+  }
+
+  /**
+   * Liefert die Schrittgroesse des Spinners.
+   */
+  public double getStepSize() {
+    return ((SpinnerNumberModel)spinner.getModel()).getStepSize().doubleValue();
+  }
+
+  /**
+   * Setzt die Schrittweiter des Spinners.
+   * @param stepSize groesster einstellbarer Spinner-Wert
+   */
+  public void setStepSize(double stepSize) {
+    setRestrictions(
+      getValue(),
+      getMinValue(),
+      getMaxValue(),
+      stepSize
+    );
+  }
+
+  /**
+   * Setzt alle Restriktionen des Sliders und Spinners neu.
+   * @param value    angezeigter Wert
+   * @param min      minimaler einstellbarer Wert
+   * @param max      maximaler einstellbarer Wert
+   * @param stepSize Schrittweite des Spinners
+   */
+  public void setRestrictions(double value, double min, double max, double stepSize) {
+    // Spinner einstellen
+    spinner.setModel( new SpinnerNumberModel(
+      value,
+      min,
+      max,
+      stepSize
+    ) );
+    spinner.setEditor( new JSpinner.NumberEditor(this.spinner,SwingUtil.getNumberFormatPattern(stepSize)) );
+    // Slider einstellen
+    slider.setMinimum( (int)Math.floor(min) );
+    slider.setMaximum( (int)Math.ceil(max) );
+    setValue( value );
+  }
+
+  /**
+   * Liefert den Slider des Panels.
+   */
+  public JSlider getSlider() {
+    return this.slider;
+  }
+
+  /**
+   * Liefert das Ueberschrift-Label des Panels.
+   */
+  public JLabel getHeaderLabel() {
+    return this.headerLabel;
+  }
+
+  /**
+   * Liefert den Spinner des Panels.
+   */
+  public JSpinner getSpinner() {
+    return this.spinner;
+  }
+}

Modified: trunk/src/schmitzm/swing/SortableJTable.java
===================================================================
--- trunk/src/schmitzm/swing/SortableJTable.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/SortableJTable.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,180 +1,199 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.swing;
-
-import java.util.Vector;
-
-import javax.swing.JTable;
-import javax.swing.ListSelectionModel;
-import javax.swing.table.TableColumnModel;
-import javax.swing.table.TableModel;
-
-/**
- * Extends the {@link JTable} with automatic sort functionality.
- * This class adds the following methods so that manually calling
- * {@link JTable#convertRowIndexToModel(int)} and {@link JTable#convertRowIndexToView(int)}
- * is not necessary:
- * <ul>
- *   <li>{@link #getEditingModelRow()}</li>
- *   <li>{@link #getSelectedModelRow()}</li>
- *   <li>{@link #getSelectedModelRows()}</li>
- *   <li>{@link #addModelRowSelectionInterval(int, int)}</li>
- *   <li>{@link #setModelRowSelectionInterval(int, int)}</li>
- *   <li>{@link #removeRowSelectionInterval(int, int)}</li>
- *   <li>{@link #changeModelSelection(int, int, boolean, boolean)}</li>
- * </ul>   
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- */
-public class SortableJTable extends SelectableJTable {
-
-  /**
-   * Creates an empty table.
-   */
-  public SortableJTable() {
-    super();
-    initTable();
-  }
-
-  /**
-   * Creates an empty table.
-   */
-  public SortableJTable(int numRows, int numColumns) {
-    super(numRows, numColumns);
-    initTable();
-  }
-
-  /**
-   * Creates a new table.
-   */
-  public SortableJTable(Object[][] rowData, Object[] columnNames) {
-    super(rowData, columnNames);
-    initTable();
-  }
-
-  /**
-   * Creates a new table.
-   */
-  public SortableJTable(TableModel dm, TableColumnModel cm, ListSelectionModel sm) {
-    super(dm, cm, sm);
-    initTable();
-  }
-
-  /**
-   * Creates a new table.
-   */
-  public SortableJTable(TableModel dm, TableColumnModel cm) {
-    super(dm, cm);
-    initTable();
-  }
-
-  /**
-   * Creates a new table.
-   */
-  public SortableJTable(TableModel dm) {
-    super(dm);
-    initTable();
-  }
-
-  /**
-   * Creates a new table.
-   */
-  public SortableJTable(Vector rowData, Vector columnNames) {
-    super(rowData, columnNames);
-    initTable();
-  }
-  
-  /**
-   * Called by every constructor to initialize the extended
-   * functionalities.
-   */
-  protected void initTable() {
-    setAutoCreateRowSorter(true);
-  }
-  
-  /**
-   * Returns the index of the currently edited row according to
-   * the table model.
-   */
-  public int getEditingModelRow() {
-    return convertRowIndexToModel(getEditingRow());
-  }
-
-  /**
-   * Returns the index of the selected row according to
-   * the table model.
-   */
-  public int getSelectedModelRow() {
-    return convertRowIndexToModel(getSelectedRow());
-  }
-
-  /**
-   * Returns the indices of the selected rows according to
-   * the table model.
-   */
-  public int[] getSelectedModelRows() {
-    int[] rows = super.getSelectedRows();
-    for (int i=0; i<rows.length; i++)
-      rows[i] = convertRowIndexToModel(rows[i]);
-    return rows;
-  }
-  
-  /**
-   * Changes the selected cells.
-   * @param row row index
-   * @param col column index
-   * @param toggle see {@link #changeSelection(int, int, boolean, boolean)}
-   * @param extend see {@link #changeSelection(int, int, boolean, boolean)}
-   */
-  public void changeModelSelection(int row, int col, boolean toggle, boolean extend) {
-    row = convertRowIndexToView(row);
-    changeSelection(row, col, toggle, extend);
-  }
-  
-  /**
-   * Extends the current selection by the given index interval
-   * according to the table model.
-   * @param index0 start index
-   * @param index1 end index (inclusive)
-   */
-  public void addModelRowSelectionInterval(int index0, int index1) {
-    for (int i=index0; i<=index1; i++) {
-      int viewIdx = convertRowIndexToView(i);
-      addRowSelectionInterval(viewIdx, viewIdx);
-    }
-  }
-
-  /**
-   * Sets the current selection to the given index interval
-   * according to the table model.
-   * @param index0 start index
-   * @param index1 end index (inclusive)
-   */
-  public void setModelRowSelectionInterval(int index0, int index1) {
-    clearSelection();
-    for (int i=index0; i<=index1; i++) {
-      int viewIdx = convertRowIndexToView(i);
-      addRowSelectionInterval(viewIdx, viewIdx);
-    }
-  }
-  
-  /**
-   * Removes the given index interval of rows from the current selection
-   * according to the table model.
-   * @param index0 start index
-   * @param index1 end index (inclusive)
-   */
-  public void removeModelRowSelectionInterval(int index0, int index1) {
-    for (int i=index0; i<=index1; i++) {
-      int viewIdx = convertRowIndexToView(i);
-      removeRowSelectionInterval(viewIdx, viewIdx);
-    }
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
+
+import java.util.Vector;
+
+import javax.swing.JTable;
+import javax.swing.ListSelectionModel;
+import javax.swing.table.TableColumnModel;
+import javax.swing.table.TableModel;
+
+/**
+ * Extends the {@link JTable} with automatic sort functionality.
+ * This class adds the following methods so that manually calling
+ * {@link JTable#convertRowIndexToModel(int)} and {@link JTable#convertRowIndexToView(int)}
+ * is not necessary:
+ * <ul>
+ *   <li>{@link #getEditingModelRow()}</li>
+ *   <li>{@link #getSelectedModelRow()}</li>
+ *   <li>{@link #getSelectedModelRows()}</li>
+ *   <li>{@link #addModelRowSelectionInterval(int, int)}</li>
+ *   <li>{@link #setModelRowSelectionInterval(int, int)}</li>
+ *   <li>{@link #removeRowSelectionInterval(int, int)}</li>
+ *   <li>{@link #changeModelSelection(int, int, boolean, boolean)}</li>
+ * </ul>   
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ */
+public class SortableJTable extends SelectableJTable {
+
+  /**
+   * Creates an empty table.
+   */
+  public SortableJTable() {
+    super();
+    initTable();
+  }
+
+  /**
+   * Creates an empty table.
+   */
+  public SortableJTable(int numRows, int numColumns) {
+    super(numRows, numColumns);
+    initTable();
+  }
+
+  /**
+   * Creates a new table.
+   */
+  public SortableJTable(Object[][] rowData, Object[] columnNames) {
+    super(rowData, columnNames);
+    initTable();
+  }
+
+  /**
+   * Creates a new table.
+   */
+  public SortableJTable(TableModel dm, TableColumnModel cm, ListSelectionModel sm) {
+    super(dm, cm, sm);
+    initTable();
+  }
+
+  /**
+   * Creates a new table.
+   */
+  public SortableJTable(TableModel dm, TableColumnModel cm) {
+    super(dm, cm);
+    initTable();
+  }
+
+  /**
+   * Creates a new table.
+   */
+  public SortableJTable(TableModel dm) {
+    super(dm);
+    initTable();
+  }
+
+  /**
+   * Creates a new table.
+   */
+  public SortableJTable(Vector rowData, Vector columnNames) {
+    super(rowData, columnNames);
+    initTable();
+  }
+  
+  /**
+   * Called by every constructor to initialize the extended
+   * functionalities.
+   */
+  protected void initTable() {
+    setAutoCreateRowSorter(true);
+  }
+  
+  /**
+   * Returns the index of the currently edited row according to
+   * the table model.
+   */
+  public int getEditingModelRow() {
+    return convertRowIndexToModel(getEditingRow());
+  }
+
+  /**
+   * Returns the index of the selected row according to
+   * the table model.
+   */
+  public int getSelectedModelRow() {
+    return convertRowIndexToModel(getSelectedRow());
+  }
+
+  /**
+   * Returns the indices of the selected rows according to
+   * the table model.
+   */
+  public int[] getSelectedModelRows() {
+    int[] rows = super.getSelectedRows();
+    for (int i=0; i<rows.length; i++)
+      rows[i] = convertRowIndexToModel(rows[i]);
+    return rows;
+  }
+  
+  /**
+   * Changes the selected cells.
+   * @param row row index
+   * @param col column index
+   * @param toggle see {@link #changeSelection(int, int, boolean, boolean)}
+   * @param extend see {@link #changeSelection(int, int, boolean, boolean)}
+   */
+  public void changeModelSelection(int row, int col, boolean toggle, boolean extend) {
+    row = convertRowIndexToView(row);
+    changeSelection(row, col, toggle, extend);
+  }
+  
+  /**
+   * Extends the current selection by the given index interval
+   * according to the table model.
+   * @param index0 start index
+   * @param index1 end index (inclusive)
+   */
+  public void addModelRowSelectionInterval(int index0, int index1) {
+    for (int i=index0; i<=index1; i++) {
+      int viewIdx = convertRowIndexToView(i);
+      addRowSelectionInterval(viewIdx, viewIdx);
+    }
+  }
+
+  /**
+   * Sets the current selection to the given index interval
+   * according to the table model.
+   * @param index0 start index
+   * @param index1 end index (inclusive)
+   */
+  public void setModelRowSelectionInterval(int index0, int index1) {
+    clearSelection();
+    for (int i=index0; i<=index1; i++) {
+      int viewIdx = convertRowIndexToView(i);
+      addRowSelectionInterval(viewIdx, viewIdx);
+    }
+  }
+  
+  /**
+   * Removes the given index interval of rows from the current selection
+   * according to the table model.
+   * @param index0 start index
+   * @param index1 end index (inclusive)
+   */
+  public void removeModelRowSelectionInterval(int index0, int index1) {
+    for (int i=index0; i<=index1; i++) {
+      int viewIdx = convertRowIndexToView(i);
+      removeRowSelectionInterval(viewIdx, viewIdx);
+    }
+  }
+}

Modified: trunk/src/schmitzm/swing/SpringUtilities.java
===================================================================
--- trunk/src/schmitzm/swing/SpringUtilities.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/SpringUtilities.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,229 +1,247 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing;
-
 import java.awt.Component;
 import java.awt.Container;
 
 import javax.swing.Spring;
 import javax.swing.SpringLayout;
-
-/**
- * Diese Klasse stellt Methoden zur Verfuegung, um {@linkplain SpringLayout SpringLayouts}
- * in Rasterform anzuordnen.<br>
- * Sie wurde aus den Beispielen
- * <a href="http://java.sun.com/docs/books/tutorial/uiswing/layout/spring.html"
- *  target="_blank">"How to Use SpringLayout"</a> der Sun-JavaDoc 1.5
- *  uebernommen (der Source-Code ist
- * <a href="http://java.sun.com/docs/books/tutorial/uiswing/layout/example-1dot4/SpringUtilities.java"
- *  target="_blank">hier</a> zu finden).<br><br>
- * <b>Nachtraegliche Anpassungen:</b>
- * <ul>
- * <li><u>Code SCHMITZ-01</u><br>
- *     Der Container muss nicht mehr so viele Komponenten besitzen, dass das
- *     Raster komplett gefuellt werden kann. Dies fuehrte urspruenglich zu
- *     einer <code>ArrayIndexOutOfBoundsException</code>.
- * </ul>
- */
-public class SpringUtilities {
-    /**
-     * A debugging utility that prints to stdout the component's
-     * minimum, preferred, and maximum sizes.
-     */
-    public static void printSizes(Component c) {
-        System.out.println("minimumSize = " + c.getMinimumSize());
-        System.out.println("preferredSize = " + c.getPreferredSize());
-        System.out.println("maximumSize = " + c.getMaximumSize());
-    }
-
-    /**
-     * Aligns the first <code>rows</code> * <code>cols</code>
-     * components of <code>parent</code> in
-     * a grid. Each component is as big as the maximum
-     * preferred width and height of the components.
-     * The parent is made just big enough to fit them all.
-     * @param rows number of rows
-     * @param cols number of columns
-     * @param initialX x location to start the grid at
-     * @param initialY y location to start the grid at
-     * @param xPad x padding between cells
-     * @param yPad y padding between cells
-     */
-    public static void makeGrid(Container container,
-                                int rows, int cols,
-                                int initialX, int initialY,
-                                int xPad, int yPad) {
-        SpringLayout layout;
-        try {
-            layout = (SpringLayout)container.getLayout();
-        } catch (ClassCastException exc) {
-            System.err.println("The first argument to makeGrid must use SpringLayout.");
-            return;
-        }
-
-        Spring xPadSpring = Spring.constant(xPad);
-        Spring yPadSpring = Spring.constant(yPad);
-        Spring initialXSpring = Spring.constant(initialX);
-        Spring initialYSpring = Spring.constant(initialY);
-//### SCHMITZM-01.sc
-//      int max = rows * cols;
-        int max = Math.min(rows*cols,container.getComponentCount());
-//### SCHMITZM-01.ec
-        //Calculate Springs that are the max of the width/height so that all
-        //cells have the same size.
-        Spring maxWidthSpring = layout.getConstraints(container.getComponent(0)).
-                                    getWidth();
-        Spring maxHeightSpring = layout.getConstraints(container.getComponent(0)).
-                                    getWidth();
-        for (int i = 1; i < max; i++) {
-            SpringLayout.Constraints cons = layout.getConstraints(
-                                            container.getComponent(i));
-
-            maxWidthSpring = Spring.max(maxWidthSpring, cons.getWidth());
-            maxHeightSpring = Spring.max(maxHeightSpring, cons.getHeight());
-        }
-
-        //Apply the new width/height Spring. This forces all the
-        //components to have the same size.
-        for (int i = 0; i < max; i++) {
-            SpringLayout.Constraints cons = layout.getConstraints(
-                                            container.getComponent(i));
-
-            cons.setWidth(maxWidthSpring);
-            cons.setHeight(maxHeightSpring);
-        }
-
-        //Then adjust the x/y constraints of all the cells so that they
-        //are aligned in a grid.
-        SpringLayout.Constraints lastCons = null;
-        SpringLayout.Constraints lastRowCons = null;
-        for (int i = 0; i < max; i++) {
-            SpringLayout.Constraints cons = layout.getConstraints(
-                                                 container.getComponent(i));
-            if (i % cols == 0) { //start of new row
-                lastRowCons = lastCons;
-                cons.setX(initialXSpring);
-            } else { //x position depends on previous component
-                cons.setX(Spring.sum(lastCons.getConstraint(SpringLayout.EAST),
-                                     xPadSpring));
-            }
-
-            if (i / cols == 0) { //first row
-                cons.setY(initialYSpring);
-            } else { //y position depends on previous row
-                cons.setY(Spring.sum(lastRowCons.getConstraint(SpringLayout.SOUTH),
-                                     yPadSpring));
-            }
-            lastCons = cons;
-        }
-
-        //Set the parent's size.
-        SpringLayout.Constraints pCons = layout.getConstraints(container);
-        pCons.setConstraint(SpringLayout.SOUTH,
-                            Spring.sum(
-                                Spring.constant(yPad),
-                                lastCons.getConstraint(SpringLayout.SOUTH)));
-        pCons.setConstraint(SpringLayout.EAST,
-                            Spring.sum(
-                                Spring.constant(xPad),
-                                lastCons.getConstraint(SpringLayout.EAST)));
-    }
-
-    /* Used by makeCompactGrid. */
-    private static SpringLayout.Constraints getConstraintsForCell(
-                                                int row, int col,
-                                                Container parent,
-                                                int cols) {
-        SpringLayout layout = (SpringLayout) parent.getLayout();
-        Component c = parent.getComponent(row * cols + col);
-        return layout.getConstraints(c);
-    }
-
-    /**
-     * Aligns the first <code>rows</code> * <code>cols</code>
-     * components of <code>parent</code> in
-     * a grid. Each component in a column is as wide as the maximum
-     * preferred width of the components in that column;
-     * height is similarly determined for each row.
-     * The parent is made just big enough to fit them all.
-     * @param rows number of rows
-     * @param cols number of columns
-     * @param initialX x location to start the grid at
-     * @param initialY y location to start the grid at
-     * @param xPad x padding between cells
-     * @param yPad y padding between cells
-     */
-    public static void makeCompactGrid(Container parent,
-                                       int rows, int cols,
-                                       int initialX, int initialY,
-                                       int xPad, int yPad) {
-        SpringLayout layout;
-        try {
-            layout = (SpringLayout)parent.getLayout();
-        } catch (ClassCastException exc) {
-            System.err.println("The first argument to makeCompactGrid must use SpringLayout.");
-            return;
-        }
-        //Align all cells in each column and make them the same width.
-        Spring x = Spring.constant(initialX);
-        for (int c = 0; c < cols; c++) {
-            Spring width = Spring.constant(0);
-//### SCHMITZM-01.sc
-//          for (int r = 0; r < rows; r++) {
-            for (int r = 0; r < rows && r*cols+c < parent.getComponentCount(); r++) {
-//### SCHMITZM-01.ec
-                width = Spring.max(width,
-                                   getConstraintsForCell(r, c, parent, cols).
-                                       getWidth());
-            }
-//### SCHMITZM-01.sc
-//          for (int r = 0; r < rows; r++) {
-            for (int r = 0; r < rows && r*cols+c < parent.getComponentCount(); r++) {
-//### SCHMITZM-01.ec
-                SpringLayout.Constraints constraints =
-                        getConstraintsForCell(r, c, parent, cols);
-                constraints.setX(x);
-                constraints.setWidth(width);
-            }
-            x = Spring.sum(x, Spring.sum(width, Spring.constant(xPad)));
-        }
-
-        //Align all cells in each row and make them the same height.
-        Spring y = Spring.constant(initialY);
-        for (int r = 0; r < rows; r++) {
-            Spring height = Spring.constant(0);
-//### SCHMITZM-01.sc
-//          for (int c = 0; c < cols; r++) {
-            for (int c = 0; c < cols && r*cols+c < parent.getComponentCount(); c++) {
-//### SCHMITZM-01.ec
-                height = Spring.max(height,
-                                    getConstraintsForCell(r, c, parent, cols).
-                                        getHeight());
-            }
-//### SCHMITZM-01.sc
-//          for (int c = 0; c < cols; r++) {
-            for (int c = 0; c < cols && r*cols+c < parent.getComponentCount(); c++) {
-//### SCHMITZM-01.ec
-                SpringLayout.Constraints constraints =
-                        getConstraintsForCell(r, c, parent, cols);
-                constraints.setY(y);
-                constraints.setHeight(height);
-            }
-            y = Spring.sum(y, Spring.sum(height, Spring.constant(yPad)));
-        }
-
-        //Set the parent's size.
-        SpringLayout.Constraints pCons = layout.getConstraints(parent);
-        pCons.setConstraint(SpringLayout.SOUTH, y);
-        pCons.setConstraint(SpringLayout.EAST, x);
-    }
-}
+
+/**
+ * Diese Klasse stellt Methoden zur Verfuegung, um {@linkplain SpringLayout SpringLayouts}
+ * in Rasterform anzuordnen.<br>
+ * Sie wurde aus den Beispielen
+ * <a href="http://java.sun.com/docs/books/tutorial/uiswing/layout/spring.html"
+ *  target="_blank">"How to Use SpringLayout"</a> der Sun-JavaDoc 1.5
+ *  uebernommen (der Source-Code ist
+ * <a href="http://java.sun.com/docs/books/tutorial/uiswing/layout/example-1dot4/SpringUtilities.java"
+ *  target="_blank">hier</a> zu finden).<br><br>
+ * <b>Nachtraegliche Anpassungen:</b>
+ * <ul>
+ * <li><u>Code SCHMITZ-01</u><br>
+ *     Der Container muss nicht mehr so viele Komponenten besitzen, dass das
+ *     Raster komplett gefuellt werden kann. Dies fuehrte urspruenglich zu
+ *     einer <code>ArrayIndexOutOfBoundsException</code>.
+ * </ul>
+ */
+public class SpringUtilities {
+    /**
+     * A debugging utility that prints to stdout the component's
+     * minimum, preferred, and maximum sizes.
+     */
+    public static void printSizes(Component c) {
+        System.out.println("minimumSize = " + c.getMinimumSize());
+        System.out.println("preferredSize = " + c.getPreferredSize());
+        System.out.println("maximumSize = " + c.getMaximumSize());
+    }
+
+    /**
+     * Aligns the first <code>rows</code> * <code>cols</code>
+     * components of <code>parent</code> in
+     * a grid. Each component is as big as the maximum
+     * preferred width and height of the components.
+     * The parent is made just big enough to fit them all.
+     * @param rows number of rows
+     * @param cols number of columns
+     * @param initialX x location to start the grid at
+     * @param initialY y location to start the grid at
+     * @param xPad x padding between cells
+     * @param yPad y padding between cells
+     */
+    public static void makeGrid(Container container,
+                                int rows, int cols,
+                                int initialX, int initialY,
+                                int xPad, int yPad) {
+        SpringLayout layout;
+        try {
+            layout = (SpringLayout)container.getLayout();
+        } catch (ClassCastException exc) {
+            System.err.println("The first argument to makeGrid must use SpringLayout.");
+            return;
+        }
+
+        Spring xPadSpring = Spring.constant(xPad);
+        Spring yPadSpring = Spring.constant(yPad);
+        Spring initialXSpring = Spring.constant(initialX);
+        Spring initialYSpring = Spring.constant(initialY);
+//### SCHMITZM-01.sc
+//      int max = rows * cols;
+        int max = Math.min(rows*cols,container.getComponentCount());
+//### SCHMITZM-01.ec
+        //Calculate Springs that are the max of the width/height so that all
+        //cells have the same size.
+        Spring maxWidthSpring = layout.getConstraints(container.getComponent(0)).
+                                    getWidth();
+        Spring maxHeightSpring = layout.getConstraints(container.getComponent(0)).
+                                    getWidth();
+        for (int i = 1; i < max; i++) {
+            SpringLayout.Constraints cons = layout.getConstraints(
+                                            container.getComponent(i));
+
+            maxWidthSpring = Spring.max(maxWidthSpring, cons.getWidth());
+            maxHeightSpring = Spring.max(maxHeightSpring, cons.getHeight());
+        }
+
+        //Apply the new width/height Spring. This forces all the
+        //components to have the same size.
+        for (int i = 0; i < max; i++) {
+            SpringLayout.Constraints cons = layout.getConstraints(
+                                            container.getComponent(i));
+
+            cons.setWidth(maxWidthSpring);
+            cons.setHeight(maxHeightSpring);
+        }
+
+        //Then adjust the x/y constraints of all the cells so that they
+        //are aligned in a grid.
+        SpringLayout.Constraints lastCons = null;
+        SpringLayout.Constraints lastRowCons = null;
+        for (int i = 0; i < max; i++) {
+            SpringLayout.Constraints cons = layout.getConstraints(
+                                                 container.getComponent(i));
+            if (i % cols == 0) { //start of new row
+                lastRowCons = lastCons;
+                cons.setX(initialXSpring);
+            } else { //x position depends on previous component
+                cons.setX(Spring.sum(lastCons.getConstraint(SpringLayout.EAST),
+                                     xPadSpring));
+            }
+
+            if (i / cols == 0) { //first row
+                cons.setY(initialYSpring);
+            } else { //y position depends on previous row
+                cons.setY(Spring.sum(lastRowCons.getConstraint(SpringLayout.SOUTH),
+                                     yPadSpring));
+            }
+            lastCons = cons;
+        }
+
+        //Set the parent's size.
+        SpringLayout.Constraints pCons = layout.getConstraints(container);
+        pCons.setConstraint(SpringLayout.SOUTH,
+                            Spring.sum(
+                                Spring.constant(yPad),
+                                lastCons.getConstraint(SpringLayout.SOUTH)));
+        pCons.setConstraint(SpringLayout.EAST,
+                            Spring.sum(
+                                Spring.constant(xPad),
+                                lastCons.getConstraint(SpringLayout.EAST)));
+    }
+
+    /* Used by makeCompactGrid. */
+    private static SpringLayout.Constraints getConstraintsForCell(
+                                                int row, int col,
+                                                Container parent,
+                                                int cols) {
+        SpringLayout layout = (SpringLayout) parent.getLayout();
+        Component c = parent.getComponent(row * cols + col);
+        return layout.getConstraints(c);
+    }
+
+    /**
+     * Aligns the first <code>rows</code> * <code>cols</code>
+     * components of <code>parent</code> in
+     * a grid. Each component in a column is as wide as the maximum
+     * preferred width of the components in that column;
+     * height is similarly determined for each row.
+     * The parent is made just big enough to fit them all.
+     * @param rows number of rows
+     * @param cols number of columns
+     * @param initialX x location to start the grid at
+     * @param initialY y location to start the grid at
+     * @param xPad x padding between cells
+     * @param yPad y padding between cells
+     */
+    public static void makeCompactGrid(Container parent,
+                                       int rows, int cols,
+                                       int initialX, int initialY,
+                                       int xPad, int yPad) {
+        SpringLayout layout;
+        try {
+            layout = (SpringLayout)parent.getLayout();
+        } catch (ClassCastException exc) {
+            System.err.println("The first argument to makeCompactGrid must use SpringLayout.");
+            return;
+        }
+        //Align all cells in each column and make them the same width.
+        Spring x = Spring.constant(initialX);
+        for (int c = 0; c < cols; c++) {
+            Spring width = Spring.constant(0);
+//### SCHMITZM-01.sc
+//          for (int r = 0; r < rows; r++) {
+            for (int r = 0; r < rows && r*cols+c < parent.getComponentCount(); r++) {
+//### SCHMITZM-01.ec
+                width = Spring.max(width,
+                                   getConstraintsForCell(r, c, parent, cols).
+                                       getWidth());
+            }
+//### SCHMITZM-01.sc
+//          for (int r = 0; r < rows; r++) {
+            for (int r = 0; r < rows && r*cols+c < parent.getComponentCount(); r++) {
+//### SCHMITZM-01.ec
+                SpringLayout.Constraints constraints =
+                        getConstraintsForCell(r, c, parent, cols);
+                constraints.setX(x);
+                constraints.setWidth(width);
+            }
+            x = Spring.sum(x, Spring.sum(width, Spring.constant(xPad)));
+        }
+
+        //Align all cells in each row and make them the same height.
+        Spring y = Spring.constant(initialY);
+        for (int r = 0; r < rows; r++) {
+            Spring height = Spring.constant(0);
+//### SCHMITZM-01.sc
+//          for (int c = 0; c < cols; r++) {
+            for (int c = 0; c < cols && r*cols+c < parent.getComponentCount(); c++) {
+//### SCHMITZM-01.ec
+                height = Spring.max(height,
+                                    getConstraintsForCell(r, c, parent, cols).
+                                        getHeight());
+            }
+//### SCHMITZM-01.sc
+//          for (int c = 0; c < cols; r++) {
+            for (int c = 0; c < cols && r*cols+c < parent.getComponentCount(); c++) {
+//### SCHMITZM-01.ec
+                SpringLayout.Constraints constraints =
+                        getConstraintsForCell(r, c, parent, cols);
+                constraints.setY(y);
+                constraints.setHeight(height);
+            }
+            y = Spring.sum(y, Spring.sum(height, Spring.constant(yPad)));
+        }
+
+        //Set the parent's size.
+        SpringLayout.Constraints pCons = layout.getConstraints(parent);
+        pCons.setConstraint(SpringLayout.SOUTH, y);
+        pCons.setConstraint(SpringLayout.EAST, x);
+    }
+}

Modified: trunk/src/schmitzm/swing/StatusDialog.java
===================================================================
--- trunk/src/schmitzm/swing/StatusDialog.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/StatusDialog.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,190 +1,208 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing;
-
-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;
-
-import javax.swing.Icon;
-import javax.swing.JButton;
-import javax.swing.JDialog;
-import javax.swing.JLabel;
-import javax.swing.JOptionPane;
-import javax.swing.JProgressBar;
-
-/**
- * Diese Klasse stellt einen modalen Status-Dialog dar. Diese besteht neben
- * einer Meldung aus einem {@linkplain JProgressBar Status-Balken} der
- * standardmaessig auf 'indeterminate' eingestellt ist
- * (siehe {@link JProgressBar#setIndeterminate(boolean)}). Darueberhinaus
- * kann der Dialog ueber einen Abbrechen-Button beendet werden. Wie auf den
- * Abbruch reagiert wird, ist durch die aufrufende Klasse zu behandeln.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class StatusDialog extends JDialog {
-  /** Dialog-Option "Abbrechen". */
-  public static final int CANCEL_OPTION = JOptionPane.CANCEL_OPTION;
-  /** Dialog-Option "Ok". */
-  public static final int OK_OPTION = JOptionPane.OK_OPTION;
-
-  /** Label in dem die Meldung angezeigt wird. */
-  protected JLabel messageLabel = null;
-  /** Status-Balken, der den Fortschritt anzeigt. */
-  protected JProgressBar progressBar  = null;
-  /** Button um den Dialog zu beenden. */
-  protected JButton button = null;
-  /** Flag signalisiert, ob der Dialog ueber den Button abgebrochen wurde. */
-  protected boolean canceled = false;
-  /**
-   * Typ des Dialogs (Stanard: {@link #CANCEL_OPTION}).
-   * @see #CANCEL_OPTION
-   * @see #OK_OPTION
-   * @see #setDialogOption(int)
-   */
-  protected int dialogOption = CANCEL_OPTION;
-
-  /**
-   * Erzeugt einen neuen Status-Dialog. Der Dialog wird relativ zum Parent-Fenster
-   * zentriert.
-   * @param parent   uebergeordnetes Fenster (kann <code>null</code> sein!)
-   * @param title    Titel fuer das Fenster
-   * @param message  Meldung, die zu dem Status-Balken angezeigt wird
-   */
-  public StatusDialog(Component parent, String title, String message) {
-    this(parent,title,message,0.5,0.5);
-  }
-
-  /**
-   * Erzeugt einen neuen Status-Dialog.
-   * @param parent   uebergeordnetes Fenster (kann <code>null</code> sein!)
-   * @param title    Titel fuer das Fenster
-   * @param message  Meldung, die zu dem Status-Balken angezeigt wird
-   * @param relX     relative horizontale Position zum Parent-Fenster
-   * @param relY     relative vertikale Position zum Parent-Fenster
-   */
-  public StatusDialog(Component parent, String title, String message, double relX, double relY) {
-    this(parent,title,message,null,relX,relY);
-  }
-  /**
-   * Erzeugt einen neuen Status-Dialog.
-   * @param parent   uebergeordnetes Fenster (kann <code>null</code> sein!)
-   * @param title    Titel fuer das Fenster
-   * @param message  Meldung, die zu dem Status-Balken angezeigt wird
-   * @param icon     Icon fuer das Status-Fenster
-   * @param relX     relative horizontale Position zum Parent-Fenster
-   * @param relY     relative vertikale Position zum Parent-Fenster
-   */
-  public StatusDialog(Component parent, String title, String message, Icon icon, double relX, double relY) {
-    super((Frame)parent,true);
-    // wenn kein uebergeordnetes Fenster angegeben ist, wird es immer
-    // im Vordergrund angezeigt
-    if ( parent==null )
-      this.setAlwaysOnTop(true);
-
-    // Vorlagen-Dialog erzeugen
-    this.messageLabel = new JLabel(message);
-    this.progressBar  = new JProgressBar(JProgressBar.HORIZONTAL,0,100);
-    this.progressBar.setIndeterminate(true);
-    this.progressBar.getPreferredSize().height = 50;
-    this.button       = new JButton();
-    setDialogOption( CANCEL_OPTION );
-
-    Vector infoComponents = new Vector<Component>();
-    insertInformationComponents(infoComponents);
-    JOptionPane  pane = new JOptionPane(
-      infoComponents.toArray(),
-      JOptionPane.INFORMATION_MESSAGE,
-      JOptionPane.DEFAULT_OPTION,
-      icon,
-      new Object[] {button}
-    );
-    JDialog dialog = pane.createDialog(parent,title);
-
-    // Dialog nach Vorlage initialisieren
-    this.setTitle( dialog.getTitle() );
-    this.getContentPane().setLayout(new BorderLayout());
-    this.getContentPane().add(dialog.getContentPane());
-    this.setDefaultCloseOperation( DO_NOTHING_ON_CLOSE );
-    this.button.addActionListener( new ActionListener() {
-      public void actionPerformed(ActionEvent e) {
-        // Wenn die Option des Dialogs auf "OK" gesetzt wurde, handelt es
-        // sich beim Button-Klick nicht um einen Abbruch!
-        canceled = (dialogOption == CANCEL_OPTION);
-        setVisible(false);
-      }
-    } );
-    pack();
-    SwingUtil.setRelativeFramePosition(this,SwingUtil.getParentWindow(parent),relX,relY);
-  }
-
-  /**
-   * Fuegt die Informations-Komponenten des Dialogs (Label und Statusbalken)
-   * in eine Liste ein. Diese werden dann (untereinander) im Dialog angezeigt.
-   * Sub-Klassen koennen diese Methode ueberschreiben und weitere Komponenten
-   * in die Liste einfuegen.<br>
-   * <b>Bemerke:</b> Der Abbruch-Button ist eine Steuerungskomponente und
-   * gehoert <b>nicht</b> zu den Elementen der Liste.
-   * @param list Liste von Komponenten, die im Dialog angezeigt werden
-   */
-  protected void insertInformationComponents(Vector<Component> list) {
-    list.add( messageLabel );
-    list.add( progressBar );
-  }
-
-  /**
-   * Liefert eine Referenz auf den Status-Balken, der im Dialog angezeigt wird.
-   * Hierueber kann dieser formatiert werden.
-   */
-  public JProgressBar getProgressBar() {
-    return progressBar;
-  }
-
-  /**
-   * Setzt die Eigenschaft des Dialog-Buttons.
-   * @param option {@link #CANCEL_OPTION} oder {@link #OK_OPTION}
-   * @exception IllegalArgumentException falls keine der Optionen
-   *            {@link #CANCEL_OPTION} oder {@link #OK_OPTION} angegeben wurde
-   */
-  public void setDialogOption(int option) {
-    switch( option ) {
-      case CANCEL_OPTION: this.button.setText(SwingUtil.RESOURCE.getString("Cancel"));
-                          break;
-      case OK_OPTION: this.button.setText(SwingUtil.RESOURCE.getString("Ok"));
-                      break;
-      default: throw new IllegalArgumentException("Unknown dialog option! Only CANCEL_OPTION or OK_OPTION allowed!");
-    }
-    this.dialogOption = option;
-  }
-
-  /**
-   * Zeigt oder verbirgt den Dialog. Beim Angezeigen wird das {@link #canceled}-Flag
-   * mit <code>false</code> initialisiert.
-   */
-  public void setVisible(boolean visible) {
-    if ( !isVisible() && visible )
-      canceled = false;
-    super.setVisible(visible);
-  }
-
-  /**
-   * Prueft, ob das Fenster durch den Button abgebrochen wurde.
-   */
-  public boolean isCanceled() {
-    return canceled;
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
+
+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;
+
+import javax.swing.Icon;
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JProgressBar;
+
+/**
+ * Diese Klasse stellt einen modalen Status-Dialog dar. Diese besteht neben
+ * einer Meldung aus einem {@linkplain JProgressBar Status-Balken} der
+ * standardmaessig auf 'indeterminate' eingestellt ist
+ * (siehe {@link JProgressBar#setIndeterminate(boolean)}). Darueberhinaus
+ * kann der Dialog ueber einen Abbrechen-Button beendet werden. Wie auf den
+ * Abbruch reagiert wird, ist durch die aufrufende Klasse zu behandeln.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class StatusDialog extends JDialog {
+  /** Dialog-Option "Abbrechen". */
+  public static final int CANCEL_OPTION = JOptionPane.CANCEL_OPTION;
+  /** Dialog-Option "Ok". */
+  public static final int OK_OPTION = JOptionPane.OK_OPTION;
+
+  /** Label in dem die Meldung angezeigt wird. */
+  protected JLabel messageLabel = null;
+  /** Status-Balken, der den Fortschritt anzeigt. */
+  protected JProgressBar progressBar  = null;
+  /** Button um den Dialog zu beenden. */
+  protected JButton button = null;
+  /** Flag signalisiert, ob der Dialog ueber den Button abgebrochen wurde. */
+  protected boolean canceled = false;
+  /**
+   * Typ des Dialogs (Stanard: {@link #CANCEL_OPTION}).
+   * @see #CANCEL_OPTION
+   * @see #OK_OPTION
+   * @see #setDialogOption(int)
+   */
+  protected int dialogOption = CANCEL_OPTION;
+
+  /**
+   * Erzeugt einen neuen Status-Dialog. Der Dialog wird relativ zum Parent-Fenster
+   * zentriert.
+   * @param parent   uebergeordnetes Fenster (kann <code>null</code> sein!)
+   * @param title    Titel fuer das Fenster
+   * @param message  Meldung, die zu dem Status-Balken angezeigt wird
+   */
+  public StatusDialog(Component parent, String title, String message) {
+    this(parent,title,message,0.5,0.5);
+  }
+
+  /**
+   * Erzeugt einen neuen Status-Dialog.
+   * @param parent   uebergeordnetes Fenster (kann <code>null</code> sein!)
+   * @param title    Titel fuer das Fenster
+   * @param message  Meldung, die zu dem Status-Balken angezeigt wird
+   * @param relX     relative horizontale Position zum Parent-Fenster
+   * @param relY     relative vertikale Position zum Parent-Fenster
+   */
+  public StatusDialog(Component parent, String title, String message, double relX, double relY) {
+    this(parent,title,message,null,relX,relY);
+  }
+  /**
+   * Erzeugt einen neuen Status-Dialog.
+   * @param parent   uebergeordnetes Fenster (kann <code>null</code> sein!)
+   * @param title    Titel fuer das Fenster
+   * @param message  Meldung, die zu dem Status-Balken angezeigt wird
+   * @param icon     Icon fuer das Status-Fenster
+   * @param relX     relative horizontale Position zum Parent-Fenster
+   * @param relY     relative vertikale Position zum Parent-Fenster
+   */
+  public StatusDialog(Component parent, String title, String message, Icon icon, double relX, double relY) {
+    super((Frame)parent,true);
+    // wenn kein uebergeordnetes Fenster angegeben ist, wird es immer
+    // im Vordergrund angezeigt
+    if ( parent==null )
+      this.setAlwaysOnTop(true);
+
+    // Vorlagen-Dialog erzeugen
+    this.messageLabel = new JLabel(message);
+    this.progressBar  = new JProgressBar(JProgressBar.HORIZONTAL,0,100);
+    this.progressBar.setIndeterminate(true);
+    this.progressBar.getPreferredSize().height = 50;
+    this.button       = new JButton();
+    setDialogOption( CANCEL_OPTION );
+
+    Vector infoComponents = new Vector<Component>();
+    insertInformationComponents(infoComponents);
+    JOptionPane  pane = new JOptionPane(
+      infoComponents.toArray(),
+      JOptionPane.INFORMATION_MESSAGE,
+      JOptionPane.DEFAULT_OPTION,
+      icon,
+      new Object[] {button}
+    );
+    JDialog dialog = pane.createDialog(parent,title);
+
+    // Dialog nach Vorlage initialisieren
+    this.setTitle( dialog.getTitle() );
+    this.getContentPane().setLayout(new BorderLayout());
+    this.getContentPane().add(dialog.getContentPane());
+    this.setDefaultCloseOperation( DO_NOTHING_ON_CLOSE );
+    this.button.addActionListener( new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        // Wenn die Option des Dialogs auf "OK" gesetzt wurde, handelt es
+        // sich beim Button-Klick nicht um einen Abbruch!
+        canceled = (dialogOption == CANCEL_OPTION);
+        setVisible(false);
+      }
+    } );
+    pack();
+    SwingUtil.setRelativeFramePosition(this,SwingUtil.getParentWindow(parent),relX,relY);
+  }
+
+  /**
+   * Fuegt die Informations-Komponenten des Dialogs (Label und Statusbalken)
+   * in eine Liste ein. Diese werden dann (untereinander) im Dialog angezeigt.
+   * Sub-Klassen koennen diese Methode ueberschreiben und weitere Komponenten
+   * in die Liste einfuegen.<br>
+   * <b>Bemerke:</b> Der Abbruch-Button ist eine Steuerungskomponente und
+   * gehoert <b>nicht</b> zu den Elementen der Liste.
+   * @param list Liste von Komponenten, die im Dialog angezeigt werden
+   */
+  protected void insertInformationComponents(Vector<Component> list) {
+    list.add( messageLabel );
+    list.add( progressBar );
+  }
+
+  /**
+   * Liefert eine Referenz auf den Status-Balken, der im Dialog angezeigt wird.
+   * Hierueber kann dieser formatiert werden.
+   */
+  public JProgressBar getProgressBar() {
+    return progressBar;
+  }
+
+  /**
+   * Setzt die Eigenschaft des Dialog-Buttons.
+   * @param option {@link #CANCEL_OPTION} oder {@link #OK_OPTION}
+   * @exception IllegalArgumentException falls keine der Optionen
+   *            {@link #CANCEL_OPTION} oder {@link #OK_OPTION} angegeben wurde
+   */
+  public void setDialogOption(int option) {
+    switch( option ) {
+      case CANCEL_OPTION: this.button.setText(SwingUtil.RESOURCE.getString("Cancel"));
+                          break;
+      case OK_OPTION: this.button.setText(SwingUtil.RESOURCE.getString("Ok"));
+                      break;
+      default: throw new IllegalArgumentException("Unknown dialog option! Only CANCEL_OPTION or OK_OPTION allowed!");
+    }
+    this.dialogOption = option;
+  }
+
+  /**
+   * Zeigt oder verbirgt den Dialog. Beim Angezeigen wird das {@link #canceled}-Flag
+   * mit <code>false</code> initialisiert.
+   */
+  public void setVisible(boolean visible) {
+    if ( !isVisible() && visible )
+      canceled = false;
+    super.setVisible(visible);
+  }
+
+  /**
+   * Prueft, ob das Fenster durch den Button abgebrochen wurde.
+   */
+  public boolean isCanceled() {
+    return canceled;
+  }
+
+}

Modified: trunk/src/schmitzm/swing/StoplightContainer.java
===================================================================
--- trunk/src/schmitzm/swing/StoplightContainer.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/StoplightContainer.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,128 +1,146 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing;
-
 import java.awt.Color;
 import java.awt.Dimension;
 
 import javax.swing.JButton;
 import javax.swing.JPanel;
-
-/**
- * Stellt eine horizontale (links rot/rechts gruen) oder vertikale
- * (oben rot/unten gruen) Rot/Gruen-Ampel dar.
- * Die Ampel wird aus zwei nebeneinander oder untereinander angeordneten
- * {@link JButton} erstellt, die deaktiviert sind, also nicht auf
- * Clicks reagieren.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class StoplightContainer extends JPanel {
-  /** beide Ampel-Lichter sind aus */
-  public static final int EMPTY = 0;
-  /** das untere (rechte) Ampel-Licht ist Gruen */
-  public static final int GREEN = 1;
-  /** das obere (linke) Ampel-Licht ist Rot */
-  public static final int RED = 2;
-
-  private CircleIcon emptyIcon;
-  private CircleIcon greenIcon;
-  private CircleIcon redIcon;
-
-  private JButton upperLight;
-  private JButton lowerLight;
-  private int mode;
-
-  /**
-   * Erzeugt eine horizontale oder vertikale Ampel.
-   * @param mode initialer Modus (EMPTY/GREEN/RED)
-   * @param width Breite der Ampel in Pixeln
-   * @param height Hoehe der Ampel in Pixeln
-   * @param vertical <code>true</code> = vertikale Anordnung; <code>false<code> = horizontale Anordnung
-   */
-  public StoplightContainer(int mode, int width, int height, boolean vertical) {
-    super();
-    setSize( new Dimension(width, height) );
-    setLayout(null);
-
-    // Durchmesser des Kreises ist 80% der Ampelbreite
-    int cirWidth = (int) (vertical ? (width * 0.8) : (height * 0.8));
-    emptyIcon = new CircleIcon(cirWidth, cirWidth, Color.lightGray);
-    greenIcon = new CircleIcon(cirWidth, cirWidth, Color.green);
-    redIcon = new CircleIcon(cirWidth, cirWidth, Color.red);
-    if (vertical) {
-      upperLight = createButton(width, height / 2, 0, 0);
-      lowerLight = createButton(width, height / 2, 0, height / 2);
-    }
-    else {
-      upperLight = createButton(width / 2, height, 0, 0);
-      lowerLight = createButton(width / 2, height, width / 2, 0);
-    }
-
-    upperLight.setEnabled(false);
-    lowerLight.setEnabled(false);
-    add(upperLight);
-    add(lowerLight);
-
-    setMode(mode);
-  }
-
-  /**
-   * Erzeugt eine vertikale Ampel.
-   * @param mode initialer Modus (EMPTY/GREEN/RED)
-   * @param width Breite der Ampel in Pixeln
-   * @param height Hoehe der Ampel in Pixeln
-   */
-  public StoplightContainer(int mode, int width, int height) {
-    this(mode, width, height, true);
-  }
-
-  private JButton createButton(int width, int height, int posX, int posY) {
-    JButton b = new JButton();
-    b.setSize(width, height);
-    b.setLocation(posX, posY);
-    return b;
-  }
-
-  /**
-   * Setzt den Modus der Ampel
-   * @param mode EMPTY, GREEN oder RED (andere Werte werden ignoriert)
-   */
-  public void setMode(int mode) {
-    this.mode = mode;
-    switch (mode) {
-      case EMPTY: {
-        upperLight.setIcon(emptyIcon);
-        lowerLight.setIcon(emptyIcon);
-        break;
-      }
-      case GREEN: {
-        upperLight.setIcon(emptyIcon);
-        lowerLight.setIcon(greenIcon);
-        break;
-      }
-      case RED: {
-        upperLight.setIcon(redIcon);
-        lowerLight.setIcon(emptyIcon);
-        break;
-      }
-    }
-  }
-
-  /**
-   * Liefert den aktuellen Modus der Ampel.
-   * @return EMPTY, GREEN oder RED.
-   */
-  public int getMode() {
-    return mode;
-  }
-}
+
+/**
+ * Stellt eine horizontale (links rot/rechts gruen) oder vertikale
+ * (oben rot/unten gruen) Rot/Gruen-Ampel dar.
+ * Die Ampel wird aus zwei nebeneinander oder untereinander angeordneten
+ * {@link JButton} erstellt, die deaktiviert sind, also nicht auf
+ * Clicks reagieren.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class StoplightContainer extends JPanel {
+  /** beide Ampel-Lichter sind aus */
+  public static final int EMPTY = 0;
+  /** das untere (rechte) Ampel-Licht ist Gruen */
+  public static final int GREEN = 1;
+  /** das obere (linke) Ampel-Licht ist Rot */
+  public static final int RED = 2;
+
+  private CircleIcon emptyIcon;
+  private CircleIcon greenIcon;
+  private CircleIcon redIcon;
+
+  private JButton upperLight;
+  private JButton lowerLight;
+  private int mode;
+
+  /**
+   * Erzeugt eine horizontale oder vertikale Ampel.
+   * @param mode initialer Modus (EMPTY/GREEN/RED)
+   * @param width Breite der Ampel in Pixeln
+   * @param height Hoehe der Ampel in Pixeln
+   * @param vertical <code>true</code> = vertikale Anordnung; <code>false<code> = horizontale Anordnung
+   */
+  public StoplightContainer(int mode, int width, int height, boolean vertical) {
+    super();
+    setSize( new Dimension(width, height) );
+    setLayout(null);
+
+    // Durchmesser des Kreises ist 80% der Ampelbreite
+    int cirWidth = (int) (vertical ? (width * 0.8) : (height * 0.8));
+    emptyIcon = new CircleIcon(cirWidth, cirWidth, Color.lightGray);
+    greenIcon = new CircleIcon(cirWidth, cirWidth, Color.green);
+    redIcon = new CircleIcon(cirWidth, cirWidth, Color.red);
+    if (vertical) {
+      upperLight = createButton(width, height / 2, 0, 0);
+      lowerLight = createButton(width, height / 2, 0, height / 2);
+    }
+    else {
+      upperLight = createButton(width / 2, height, 0, 0);
+      lowerLight = createButton(width / 2, height, width / 2, 0);
+    }
+
+    upperLight.setEnabled(false);
+    lowerLight.setEnabled(false);
+    add(upperLight);
+    add(lowerLight);
+
+    setMode(mode);
+  }
+
+  /**
+   * Erzeugt eine vertikale Ampel.
+   * @param mode initialer Modus (EMPTY/GREEN/RED)
+   * @param width Breite der Ampel in Pixeln
+   * @param height Hoehe der Ampel in Pixeln
+   */
+  public StoplightContainer(int mode, int width, int height) {
+    this(mode, width, height, true);
+  }
+
+  private JButton createButton(int width, int height, int posX, int posY) {
+    JButton b = new JButton();
+    b.setSize(width, height);
+    b.setLocation(posX, posY);
+    return b;
+  }
+
+  /**
+   * Setzt den Modus der Ampel
+   * @param mode EMPTY, GREEN oder RED (andere Werte werden ignoriert)
+   */
+  public void setMode(int mode) {
+    this.mode = mode;
+    switch (mode) {
+      case EMPTY: {
+        upperLight.setIcon(emptyIcon);
+        lowerLight.setIcon(emptyIcon);
+        break;
+      }
+      case GREEN: {
+        upperLight.setIcon(emptyIcon);
+        lowerLight.setIcon(greenIcon);
+        break;
+      }
+      case RED: {
+        upperLight.setIcon(redIcon);
+        lowerLight.setIcon(emptyIcon);
+        break;
+      }
+    }
+  }
+
+  /**
+   * Liefert den aktuellen Modus der Ampel.
+   * @return EMPTY, GREEN oder RED.
+   */
+  public int getMode() {
+    return mode;
+  }
+}

Modified: trunk/src/schmitzm/swing/SwingUtil.java
===================================================================
--- trunk/src/schmitzm/swing/SwingUtil.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/SwingUtil.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,748 +1,766 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing;
-
-import java.awt.BorderLayout;
-import java.awt.Color;
-import java.awt.Component;
-import java.awt.Container;
-import java.awt.Cursor;
-import java.awt.Dimension;
-import java.awt.Frame;
-import java.awt.GridBagConstraints;
-import java.awt.Image;
-import java.awt.Point;
-import java.awt.Toolkit;
-import java.awt.Window;
-import java.text.NumberFormat;
-import java.util.Enumeration;
-import java.util.Locale;
-import java.util.Random;
-import java.util.StringTokenizer;
-
-import javax.imageio.ImageIO;
-import javax.swing.AbstractButton;
-import javax.swing.ImageIcon;
-import javax.swing.JDialog;
-import javax.swing.JFrame;
-import javax.swing.JInternalFrame;
-import javax.swing.JLabel;
-import javax.swing.JScrollPane;
-import javax.swing.JTree;
-import javax.swing.tree.TreeNode;
-import javax.swing.tree.TreePath;
-
-import org.apache.log4j.Logger;
-
-import schmitzm.lang.LangUtil;
-import schmitzm.lang.ResourceProvider;
-
-/**
- * Diese Klasse beinhaltet statische Hilfsfunktionen fuer das Arbeiten
- * mit Swing-GUIs.
- *
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
- *
- * @version 1.1
- */
-public class SwingUtil {
-  private static final Logger LOGGER = Logger.getLogger( SwingUtil.class.getClass().getName() );
-
-  /**
-	 * {@link ResourceProvider}, der die Lokalisation fuer GUI-Komponenten des
-	 * Package {@code schmitzm.swing} zur Verfuegung stellt. Diese sind in
-	 * properties-Dateien unter {@code schmitzm.swing.resource.locales}
-	 * hinterlegt.
-	 */
-	public static ResourceProvider RESOURCE = new ResourceProvider(LangUtil
-			.extendPackagePath(SwingUtil.class,
-					"resource.locales.SwingResourceBundle"), Locale.ENGLISH);
-
-	/**
-	 * Convenience method to access the translation resources.
-	*/
-	public static String R(String key, Object... values) {
-		return RESOURCE.getString(key, values);
-	}
-
-  //****************************************************************************
-  // Diese Icons sind auf Basis der Icons von Gimp erstellt
-  // Eine Sammlung aller Gimp-Icons liegt im svn: gimp-tool-cursors.xcf
-  //****************************************************************************
-  /** Cursor in Form einer Lupe mit Plus Symbol */
-  public static final Cursor ZOOMIN_CURSOR = 	createCursorFromResourcePath("resource/cursor/zoom_in.gif",8,8,null);
-  /** Cursor in Form einer Lupe mit Minus Symbol */
-  public static final Cursor ZOOMOUT_CURSOR = 	createCursorFromResourcePath("resource/cursor/zoom_out.gif",8,8,null);
-  /** Cursor in Form einer Lupe ohne Symbol*/
-  public static final Cursor ZOOM_CURSOR = 		createCursorFromResourcePath("resource/cursor/zoom.gif",8,8,null);
-  /** Cursor in Form einer offenen Hand **/
-  public static final Cursor PAN_CURSOR = 		createCursorFromResourcePath("resource/cursor/hand_pan.png",9,11,null);
-  /** Cursor in Form einer geschlossenen Hand **/
-  public static final Cursor PANNING_CURSOR = 	createCursorFromResourcePath("resource/cursor/hand_closed.png",9,11,null);
-  /** Cursor in Form einer geschlossenen Hand **/
-  public static final Cursor CROSSHAIR_CURSOR = createCursorFromResourcePath("resource/cursor/crosshair.gif",10,10,null);
-
-//  public static final ImageIcon ICON_RASTER = createImageIconFromResourcePath("resource/icon/small/raster.png","");
-//  public static final ImageIcon ICON_VECTOR = createImageIconFromResourcePath("resource/icon/small/vector.png","");
-
-
-  /** Modus "Innen".
-   *  @see #setRelativeFramePosition(Window,Window,int,int) */
-  public static final int BOUNDS_INNER = 10;
-  /** Modus "Aussen".
-   *  @see #setRelativeFramePosition(Window,Window,int,int) */
-  public static final int BOUNDS_OUTER = 20;
-  /** Ausrichtung oben-mitte. */
-  public static final int NORTH = GridBagConstraints.NORTH;
-  /** Ausrichtung oben-links. */
-  public static final int NORTHWEST = GridBagConstraints.NORTHWEST;
-  /** Ausrichtung oben-rechts. */
-  public static final int NORTHEAST = GridBagConstraints.NORTHEAST;
-  /** Ausrichtung unten-mitte. */
-  public static final int SOUTH = GridBagConstraints.SOUTH;
-  /** Ausrichtung unten-links. */
-  public static final int SOUTHWEST = GridBagConstraints.SOUTHWEST;
-  /** Ausrichtung unten-rechts. */
-  public static final int SOUTHEAST = GridBagConstraints.SOUTHEAST;
-  /** Ausrichtung zentriert. */
-  public static final int CENTER = GridBagConstraints.CENTER;
-  /** Ausrichtung mitte-links. */
-  public static final int WEST = GridBagConstraints.WEST;
-  /** Ausrichtung mitte-rechts. */
-  public static final int EAST = GridBagConstraints.EAST;
-
-  /**
-   * Erzeugt ein Icon auf Basis einer relativen Pfad-Angabe. Als Basis-Verzeichnis
-   * wird der Classpath von {@code SwingUtil} verwendet.
-   * @param imgPath relativer Pfad des Icons
-   * @param imgDesc Beschreibung fuer Icon
-   * @return {@code null}, wenn das Icon nicht gefunden wird
-   */
-  public static ImageIcon createImageIconFromResourcePath(String imgPath, String imgDesc) {
-    return createImageIconFromResourcePath(null,imgPath,imgDesc);
-  }
-
-  /**
-   * Erzeugt ein Icon  auf Basis einer relativen Pfad-Angabe.
-   * @param resourceBase Klasse, deren Classpath als Basis-Verzeichnis verwendet wird
-   * @param imgPath relativer Pfad des Icons
-   * @param imgDesc Beschreibung fuer Icon
-   * @return {@code null}, wenn das Icon nicht gefunden wird
-   */
-  public static ImageIcon createImageIconFromResourcePath(Class resourceBase, String imgPath, String imgDesc) {
-    if ( resourceBase == null )
-      resourceBase = SwingUtil.class;
-    java.net.URL imgURL = resourceBase.getResource(imgPath);
-    if (imgURL == null) {
-      LOGGER.error("Couldn't find image file: " + imgPath);
-      return null;
-    }
-    return new ImageIcon(imgURL, imgDesc);
-  }
-
-  /**
-   * Erzeugt einen {@link Cursor} auf Basis einer relativen Pfad-Angabe.
-   * Als Basis-Verzeichnis wird der Classpath von {@code SwingUtil} verwendet.
-   * @param imgPath relativer Pfad des Icons
-   * @param x       X-Position im Image, die den Hotspot des Cursors darstellen soll
-   * @param y       Y-Position im Image, die den Hotspot des Cursors darstellen soll
-   * @param name    Bezeichnung fuer den Cursor
-   * @return {@code null}, wenn das Icon nicht gefunden wird
-   */
-  public static Cursor createCursorFromResourcePath(String imgPath, int x, int y, String name) {
-    java.net.URL imgURL = SwingUtil.class.getResource(imgPath);
-    try {
-      return Toolkit.getDefaultToolkit().createCustomCursor(
-          ImageIO.read(imgURL),
-          new Point(x, y),
-          name
-      );
-    } catch( Exception err ) {
-      return null;
-    }
-  }
-
-  /**
-   * Erzeugt ein neues Fenster mit {@link BorderLayout} und zeigt darin
-   * eine {@link Component} an.
-   * @param comp anzuzeigende Komponente (kann {@code null} sein)
-   * @param title Titel des Fensters (kann {@code null} sein)
-   * @param icon Icon-Image (kann {@code null} sein)
-   */
-  public static JFrame createFrame(Component comp, String title, Image icon) {
-    JFrame frame = new JFrame( title );
-    frame.getContentPane().setLayout( new BorderLayout() );
-    if ( comp != null )
-      frame.getContentPane().add( comp, BorderLayout.CENTER );
-    if ( title != null )
-      frame.setTitle( title );
-    if ( icon != null )
-      frame.setIconImage( icon );
-    frame.pack();
-    return frame;
-  }
-
-  /**
-   * Zeigt ein neues Fenster einer {@link Component} an.
-   * @param comp anzuzeigende Komponente (kann {@code null} sein)
-   * @param title Titel des Fensters (kann {@code null} sein)
-   * @param icon Icon-Image (kann {@code null} sein)
-   * @see #createFrame(Component, String, Image)
-   */
-  public static JFrame showFrame(Component comp, String title, Image icon) {
-    JFrame frame = createFrame(comp,title,icon);
-    frame.setVisible( true );
-    return frame;
-  }
-
-  /**
-	 * Liefert das Fenster, das eine GUI-Komponente beinhaltet. Wenn
-	 * GUI-Komponente selber ein {@link Window} ist, wird diese zurückgelifert.
-	 * 
-	 * @param comp
-	 *            eine GUI-Komponente
-	 * @return <code>null</code> falls die Komponente in keinem Fenster
-	 *         enthalten ist
-	 */
-	public static Window getParentWindow(Component comp) {
-		// durch die Parents laufen, bis Window gefunden
-		while (comp != null && !(comp instanceof Window))
-			comp = comp.getParent();
-		// wenn kein Window gefunden -> null zurueckgeben
-		if (comp == null)
-			return null;
-		return (Window) comp;
-	}
-
-  /**
-   * Liefert den {@link Frame}, das eine Kompoenente beinhaltet.
-   * @param comp eine GUI-Komponente
-   * @return <code>null</code> falls die Komponente in keinem {@link Frame}
-   *         enthalten ist
-   */
-  public static Frame getParentFrame(Component comp) {
-    // durch die Parents laufen, bis Frame gefunden
-    while ( comp!=null && !(comp instanceof Frame) )
-      comp = comp.getParent();
-    // wenn kein Frame gefunden -> null zurueckgeben
-    if ( comp== null )
-      return null;
-    return (Frame)comp;
-  }
-
-  /**
-   * Liefert das Fenster, das eine Kompoenente beinhaltet. Dabei kann es sich
-   * auch um einen {@link JInternalFrame} handelt.
-   * @param comp eine GUI-Komponente
-   * @return <code>null</code> falls die Komponente in keinem Fenster
-   *         enthalten ist
-   */
-  public static Component getParentWindowComponent(Component comp) {
-    // durch die Parents laufen, bis Window gefunden
-    while ( comp!=null && !(comp instanceof Window) && !(comp instanceof JInternalFrame))
-      comp = comp.getParent();
-    // wenn kein Window gefunden -> null zurueckgeben
-    if ( comp== null )
-      return null;
-    return comp;
-  }
-
-  /**
-   * Packt das Fenster, in dem eine Kompoenente plaziert ist.
-   * @param comp eine GUI-Komponente
-   * @return <code>false</code> falls die Komponente in keinem Fenster
-   *         enthalten ist
-   * @see Window#pack()
-   */
-  public static boolean packParentWindow(Component comp) {
-    Window w = getParentWindow(comp);
-    if ( w == null )
-      return false;
-    w.pack();
-    return true;
-  }
-
-  /**
-   * Prueft, ob eine Komponente eine Kind-Komponente einer anderen Komponente ist.
-   * @param child Component
-   * @param parent Component
-   * @return {@code false} wenn {@code child == null}, {@code true} wenn {@code child == parent},
-   *         {@code isChildComponent(child.getParent(),parent)} sonst
-   */
-  public static boolean isChildComponent(Component child, Component parent) {
-    if ( child == null )
-      return false;
-    if ( child == parent )
-      return true;
-    return isChildComponent(child.getParent(),parent);
-  }
-
-  /**
-   * Zentriert ein Fenster auf dem Monitor.
-   * @param window das zu zentrierende Fenster
-   */
-  public static void centerFrameOnScreen(Component comp) {
-      setRelativeFramePosition(comp,0.5,0.5);
-  }
-
-  /**
-   * Zentriert ein Fenster auf dem Monitor.<br>
-   * <b>Bemerkung:</b> Da {@link Window} eine {@link Component} ist, ist diese
-   * Methode eigentlich ueberfluessig. Es koennte {@link #centerFrameOnScreen(Component)}
-   * verwendet werden. Merkwuerdigerweise macht XULU beim Starten von der Console
-   * aus aber Probleme, wenn die Methode {@code centerFrameOnScreen(Window)} fehlt!!
-   * TODO: Probleme beim Xulu-Start loesen.
-   * @param window das zu zentrierende Fenster
-   */
-  public static void centerFrameOnScreen(Window comp) {
-      setRelativeFramePosition(comp,0.5,0.5);
-  }
-
-  /**
-   * Zentriert ein Fenster auf dem Monitor, aber verrückt das Window per Zufall um 10 Prozenz
-   *
-   * @param comp Eine Componente des zu zentrierenden Fensters. Wenn comp kein {@link Window} ist, wird das Parent {@link Window} ermittelt.
-   *
-   * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
-   */
-  public static void centerFrameOnScreenRandom(Component comp) {
-	  Random r = new Random();
-      setRelativeFramePosition(comp,0.5 + (r.nextDouble()*0.2-0.1) , 0.5 + (r.nextDouble()*0.2-0.1));
-  }
-
-
-  /**
-   * Positioniert ein Fenster auf dem Monitor, relativ zu dessen Groesse. (0.5/0.5)
-   * positioniert das Fenster z.B. genau in der Mitte des Monitors; (0.25/0.5)
-   * setzt das Fenster vertikal in die Mitte und horizontal auf ein Viertel der
-   * Monitorbreite.
-   * @param comp Eine Komponente des zu positionierenden Fensters oder direckt das {@link Window}. 
-   * @param relX  Relationsfaktor fuer die horizontale Position (0 < <code>relX</code> < 1)
-   * @param relY  Relationsfaktor fuer die vertikale Position (0 < <code>relX</code> < 1)
-   */
-  public static void setRelativeFramePosition(Component comp, double relX, double relY) {
-	  
-      setRelativeFramePosition(comp,null,relX,relY);
-  }
-
-  /**
-   * Positioniert ein Fenster auf dem Monitor relativ zur Position eines
-   * anderen Fensters. (0.5/0.5) positioniert das Fenster z.B. genau in der Mitte
-   * anderen Fensters. (0.25/0.5) setzt das Fenster vertikal in die Mitte und
-   * horizontal auf ein Viertel des Referenz-Fensters.
-   * @param comp Eine Komponente des zu positionierenden Fensters oder direkt das {@link Window}.
-   * @param relFrame Fenster zu dem das Fenster in Relation gesetzt wird (wenn
-   *                 <code>null</code> wird der gesamte Monitor verwendet)
-   * @param relX  Relationsfaktor fuer die horizontale Position (0 < <code>relX</code> < 1)
-   * @param relY  Relationsfaktor fuer die vertikale Position (0 < <code>relY</code> < 1)
-   */
-  public static void setRelativeFramePosition(Component comp, Window relFrame, double relX, double relY) {
-	 
-	  // Added by SK, 17.4.2009
-	  // sk.sc
-	  Window window;
-	  if (comp instanceof Window){
-		  window = (Window) comp;
-	  } else {
-		  window = SwingUtil.getParentWindow(comp);
-	  }
-	  // sk.ec
-	  
-      Dimension screenSize  = Toolkit.getDefaultToolkit().getScreenSize();
-      Dimension relSize     = (relFrame==null) ? screenSize : relFrame.getSize();
-      Point     relLocation = (relFrame==null) ? new Point(0,0) : relFrame.getLocation();
-
-      // Fenster auf Monitor-Groesse anpassen
-      Dimension frameSize = window.getSize();
-      if (frameSize.height > screenSize.height) {
-        frameSize.height = screenSize.height;
-      }
-      if (frameSize.width > screenSize.width) {
-        frameSize.width = screenSize.width;
-      }
-      // Fenster positionieren
-      window.setLocation( relLocation.x + Math.round( (relSize.width-frameSize.width)*(float)relX ),
-                         relLocation.y + Math.round( (relSize.height-frameSize.height)*(float)relY )
-      );
-  }
-
-  /**
-   * Positioniert ein Fenster auf dem Monitor relativ zur Position eines
-   * anderen Fensters. Das Fenster wird jedoch immer innerhalb des Bildschirms
-   * positioniert.
-   * @param window das zu positionierende Fenster
-   * @param relWindow Fenster zu dem das Fenster in Relation gesetzt wird (wenn
-   *                 <code>null</code> wird der gesamte Monitor verwendet)
-   * @param type bestimmt, ob das Fenster innerhalb oder ausserhalb des relativen
-   *                       Fensters positioniert wird ({@link #BOUNDS_INNER} oder {@link #BOUNDS_OUTER}).
-   * @param position Positionierung des Fensters ({@link #NORTH}, {@link #NORTHEAST}, ...)
-   */
-  public static void setRelativeFramePosition(Window window, Window relWindow, int type, int position) {
-    if ( type == BOUNDS_INNER ) {
-      // An den inneren Grenzen des Frames ausrichten
-      double relX = 0;
-      double relY = 0;
-      switch ( position ) {
-        case NORTH:     relX = 0.5; relY = 0.0; break;
-        case NORTHWEST: relX = 0.0; relY = 0.0; break;
-        case NORTHEAST: relX = 1.0; relY = 0.0; break;
-        case SOUTH:     relX = 0.5; relY = 1.0; break;
-        case SOUTHWEST: relX = 0.0; relY = 1.0; break;
-        case SOUTHEAST: relX = 1.0; relY = 1.0; break;
-        case CENTER:    relX = 0.5; relY = 0.5; break;
-        case WEST:      relX = 0.0; relY = 0.5; break;
-        case EAST:      relX = 1.0; relY = 0.5; break;
-        default: throw new IllegalArgumentException("Unsupported mode for 'position'.");
-      }
-      setRelativeFramePosition(window,relWindow,relX,relY);
-      return;
-    }
-    if ( type == BOUNDS_OUTER ) {
-      Dimension screenSize  = Toolkit.getDefaultToolkit().getScreenSize();
-      Dimension relSize     = (relWindow==null) ? screenSize : relWindow.getSize();
-      Point     relLocation = (relWindow==null) ? new Point(0,0) : relWindow.getLocation();
-      // An den Aussen-Grenzen des Frames ausrichten
-      Point    loc = new Point(0,0);
-      switch ( position ) {
-        case NORTH:
-        case NORTHWEST:
-        case NORTHEAST: loc.y = relLocation.y - window.getHeight(); break;
-        case SOUTH:
-        case SOUTHWEST:
-        case SOUTHEAST: loc.y = relLocation.y + relSize.height; break;
-        case CENTER:
-        case WEST:
-        case EAST:      loc.y = relLocation.y + relSize.height/2 - window.getHeight()/2; break;
-        default: throw new IllegalArgumentException("Unsupported mode for 'position'.");
-      }
-      switch ( position ) {
-        case WEST:
-        case NORTHWEST:
-        case SOUTHWEST: loc.x = relLocation.x - window.getWidth(); break;
-        case EAST:
-        case NORTHEAST:
-        case SOUTHEAST: loc.x = relLocation.x + relSize.width; break;
-        case CENTER:
-        case NORTH:
-        case SOUTH:     loc.x = relLocation.x + relSize.width/2 - window.getWidth()/2; break;
-        default: throw new IllegalArgumentException("Unsupported mode for 'position'. GridBagConstraints location expected!");
-      }
-
-      loc.x = Math.max(0,loc.x);
-      loc.y = Math.max(0,loc.y);
-      if ( loc.x + window.getWidth() > screenSize.width )
-        loc.x = screenSize.width - window.getWidth();
-      if ( loc.y + window.getHeight() > screenSize.height )
-        loc.y = screenSize.height - window.getHeight();
-
-      // Fenster positionieren
-      window.setLocation( loc );
-      return;
-    }
-    throw new IllegalArgumentException("Unsupported mode for 'type'. BOUNDS_INNER or BOUNDS_OUTER expected!");
-  }
-
-  /**
-   * Aendert die Breite einer GUI-Komponente.
-   * @param comp GUI-Komponente
-   * @param w    Breite
-   */
-  public static void setWidth(Component comp, int w) {
-    Dimension d = comp.getPreferredSize();
-    d.width = w;
-    comp.setSize(d);
-  }
-
-  /**
-   * Aendert die Hoehe einer GUI-Komponente.
-   * @param comp GUI-Komponente
-   * @param h    Hoehe
-   */
-  public static void setHeight(Component comp, int h) {
-    Dimension d = comp.getPreferredSize();
-    d.height = h;
-    comp.setSize(d);
-  }
-
-  /**
-   * Aendert die bevorzugte Breite einer GUI-Komponente.
-   * @param comp GUI-Komponente
-   * @param w    Breite
-   */
-  public static void setPreferredWidth(Component comp, int w) {
-    Dimension d = comp.getPreferredSize();
-    d.width = w;
-    comp.setPreferredSize(d);
-  }
-
-  /**
-   * Aendert die bevorzugte Hoehe einer GUI-Komponente.
-   * @param comp GUI-Komponente
-   * @param h    Hoehe
-   */
-  public static void setPreferredHeight(Component comp, int h) {
-    Dimension d = comp.getPreferredSize();
-    d.height = h;
-    comp.setPreferredSize(d);
-  }
-
-  /**
-   * Aendert die minimal erlaubte Breite einer GUI-Komponente.
-   * @param comp GUI-Komponente
-   * @param w    Breite
-   * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
-   */
-  public static void setMinimumWidth(Component comp, int w) {
-	  Dimension d = comp.getMinimumSize();
-	  d.width = w;
-	  comp.setMinimumSize(d);
-  }
-
-  /**
-   * Aendert die minimal erlaubte Hoehe einer GUI-Komponente.
-   * @param comp GUI-Komponente
-   * @param h    Hoehe
-   * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
-   */
-  public static void setMinimumHeight(Component comp, int h) {
-	  Dimension d = comp.getMinimumSize();
-	  d.height = h;
-	  comp.setMinimumSize(d);
-  }
-
-  /**
-   * Aendert die maximal erlaubte Breite einer GUI-Komponente.
-   * @param comp GUI-Komponente
-   * @param w    Breite
-   */
-  public static void setMaximumWidth(Component comp, int w) {
-    Dimension d = comp.getMaximumSize();
-    d.width = w;
-    comp.setMaximumSize(d);
-  }
-
-  /**
-   * Aendert die maximal erlaubte Hoehe einer GUI-Komponente.
-   * @param comp GUI-Komponente
-   * @param h    Hoehe
-   */
-  public static void setMaximumHeight(Component comp, int h) {
-    Dimension d = comp.getMaximumSize();
-    d.height = h;
-    comp.setMaximumSize(d);
-  }
-
-  /**
-   * Fixiert die Groesse einer GUI-Komponente.
-   * @param comp GUI-Komponente
-   * @param d Ausmasse (Hoehe und Breite)
-   */
-  public static void fixComponentSize(Component comp, Dimension d) {
-    comp.setPreferredSize(d);
-    comp.setMinimumSize(d);
-    comp.setMaximumSize(d);
-  }
-
-  /**
-   * Fixiert die Groesse einer GUI-Komponente mit der aktuell
-   * bevorzugten Groesse.
-   * @param comp GUI-Komponente
-   */
-  public static void fixComponentSize(Component comp) {
-    fixComponentSize(comp, comp.getPreferredSize());
-  }
-
-  /***
-   * Setzt die Hintergrundfarbe einer Komponente und aller darin enthaltener
-   * Komponenten.
-   * @param comp Komponente
-   * @param color neue Hintergrund-Farbe
-   */
-  public static void setAllBackground(Component comp, Color color) {
-    comp.setBackground( color );
-    if ( comp instanceof JFrame )
-      setAllBackground( ((JFrame)comp).getContentPane(), color );
-    if ( comp instanceof JScrollPane )
-      setAllBackground( ((JScrollPane)comp).getViewport(), color );
-    else if ( comp instanceof Container )
-      for ( Component innerComp : ((Container)comp).getComponents() )
-        setAllBackground( innerComp, color );
-  }
-
-  /**
-   * Versucht, aus einem String eine Farbe zu erstellen. Drei Moeglichekeiten
-   * gibt es fuer das Format des Strings:
-   * <ol>
-   *   <li><code>"RGB(<i>red</i>,<i>green</i>,<i>blue</i>)"</code><br>
-   *       wobei <i>red</i>,<i>green</i> und <i>blue</i> dezimale Werte
-   *       zwischen 0 und 255 sind.</li>
-   *   <li>Der String stellt einen Integer-Wert im dezimalen, oktalen oder
-   *       hexadezimalen Format dar, aus dem die 3 RGB-Werte extrahiert werden
-   *       (siehe {@link Color#decode(String) Color.decode(..)}).</li>
-   *   <li>Der String spezifiziert ein statisches Feld der Klasse {@link Color}.<br>
-   *       z.B. steht <code>"RED"</code> fuer {@link Color#RED Color.RED},
-   *            <code>"darkGray"</code> fuer {@link Color#darkGray Color.darkGray} oder
-   *            <code>"LIGHT_GRAY"</code> fuer {@link Color#LIGHT_GRAY Color.LIGHT_GRAY}</li>
-   * </ol>
-   *
-   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-   *
-   * @throws IllegalArgumentException wenn der uebergebene String nicht interpretiert werden kann.
-   *
-   */
-  // Schmeisst nur noch IllegalArgumentException, vorher Exception. (SK) 21.08.2007
-  public static Color parseColor(String colorStr) throws IllegalArgumentException {
-    // Wenn String mit "RGB(" startet, Format RGB(<r>,<b>,<g>) parsen
-    if ( colorStr.toUpperCase().startsWith("RGB(") )
-      try {
-        StringTokenizer tok = new StringTokenizer(colorStr.substring(4));
-        int r = Integer.parseInt(tok.nextToken(",()\n"));
-        int g = Integer.parseInt(tok.nextToken(",()\n"));
-        int b = Integer.parseInt(tok.nextToken(",()\n"));
-        return new Color(r,g,b);
-      } catch (Exception err) {
-        throw new IllegalArgumentException("Invalid RGB-specification. RGB(<r>,<g>,<b>) expected.",err);
-      }
-
-    // Versucht, die Farbe als dezimalen, oktalen oder hexadezimalen Integer
-    // einzulesen
-    Long testLong = null;
-    try {
-      testLong = Long.decode(colorStr);
-      return Color.decode(colorStr);
-    } catch (NumberFormatException err) {
-      // wenn 'testLong' ein gueltiger Long ist, handelt es sich zwar um
-      // eine gueltige Zahl, aber kein passendes Integer-Format nicht!
-      if ( testLong != null )
-        throw new IllegalArgumentException(colorStr + " is not a valid RGB-Integer in decimal, octal or hexadecimal format.");
-    }
-
-    // Wenn auch kein Integer angegeben wurde, wird versucht, die Farbe
-    // als Feld von java.awt.Color zu interpretieren
-    try {
-      return (Color)Color.class.getDeclaredField(colorStr).get(null);
-    } catch ( Exception err1 ) {
-      try {
-        // als letztes noch versuchen, die Farbe in Gross-Buchstaben zu finden
-        return (Color) Color.class.getDeclaredField(colorStr.toUpperCase()).get(null);
-      } catch ( Exception err2 ) {
-        throw new IllegalArgumentException(colorStr + " is not a valid color name. Name of a static field of class java.awt.Color expected.");
-      }
-    }
-  }
-
-  /**
-   * Setzt das Label eine Componente neu. Macht nichts, falls {@code newLabel}
-   * oder {@code comp} den Wert {@code null} hat.
-   * @param comp {@link JLabel}, {@link AbstractButton}, {@link JDialog} oder
-   *             {@link Frame}
-   * @param newLabel neue Beschriftung
-   * @exception UnsupportedOperationException falls {@code comp} nicht
-   *            unterstuetzt wird.
-   *
-   */
-  public static void resetCaption(Component comp, Object newLabel) {
-    if ( comp == null || newLabel == null )
-      return;
-    if ( comp instanceof JLabel )
-      ((JLabel)comp).setText( newLabel.toString() );
-    else if ( comp instanceof AbstractButton )
-      ((AbstractButton)comp).setText( newLabel.toString() );
-    else if ( comp instanceof Frame )
-      ((Frame)comp).setTitle( newLabel.toString() );
-    else if ( comp instanceof JDialog )
-      ((JDialog)comp).setTitle( newLabel.toString() );
-    else
-      throw new UnsupportedOperationException(SwingUtil.class.getSimpleName()+"resetCaption(.) can not be applied to "+comp.getClass().getSimpleName());
-  }
-
-  /**
-   * Erstellt das Pattern fuer ein {@link NumberFormat}.
-   * @param sample Beispiel-Wert, der die Anzahl der dargestellten Nachkomma-Stellen
-   *               bestimmt
-   */
-  public static String getNumberFormatPattern(double sample) {
-    String format = "0";
-    for (int i=0; sample != (int)sample; i++ ) {
-      if ( i==0 )
-        format += ".";
-      sample *= 10;
-      format += "0";
-    }
-    return format;
-  }
-
-  /**
-   * Erstellt das Pattern fuer ein {@link NumberFormat}.
-   * @param digits Anzahl der dargestellten Nachkomma-Stellen
-   */
-  public static String getNumberFormatPattern(int digits) {
-    String format = "0";
-    for (int i=0; i<digits; i++ ) {
-      if ( i==0 )
-        format += ".";
-      format += "0";
-    }
-    return format;
-  }
-
-  /**
-   * Copied from http://www.exampledepot.com/egs/javax.swing.tree/ExpandAll.html
-   * e1029. Expanding or Collapsing All Nodes in a JTree Component
-   * If expand is true, expands all nodes in the tree.
-   * Otherwise, collapses all nodes in the tree.
-   * @param tree {@link JTree} to expand or collapse
-   */
-  public static void expandAll(JTree tree, boolean expand) {
-      TreeNode root = (TreeNode)tree.getModel().getRoot();
-
-      // Traverse tree from root
-      expandAll(tree, new TreePath(root), expand);
-  }
-  private static void expandAll(JTree tree, TreePath parent, boolean expand) {
-      // Traverse children
-      TreeNode node = (TreeNode)parent.getLastPathComponent();
-      if (node.getChildCount() >= 0) {
-          for (Enumeration e=node.children(); e.hasMoreElements(); ) {
-              TreeNode n = (TreeNode)e.nextElement();
-              TreePath path = parent.pathByAddingChild(n);
-              expandAll(tree, path, expand);
-          }
-      }
-
-      // Expansion or collapse must be done bottom-up
-      if (expand) {
-          tree.expandPath(parent);
-      } else {
-          tree.collapsePath(parent);
-      }
-  }
-
-  /**
-   * This method maximizes a frame; the iconified bit is not affected
-   * Taken from e564. Iconifying and Maximizing a Frame,
-   * http://www.exampledepot.com/egs/java.awt/frame_FrameIconify.html
-   *
-   * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
-   */
-  public static void maximize(Frame frame) {
-      int state = frame.getExtendedState();
-
-      // Set the maximized bits
-      state |= Frame.MAXIMIZED_BOTH;
-
-      // Maximize the frame
-      frame.setExtendedState(state);
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Container;
+import java.awt.Cursor;
+import java.awt.Dimension;
+import java.awt.Frame;
+import java.awt.GridBagConstraints;
+import java.awt.Image;
+import java.awt.Point;
+import java.awt.Toolkit;
+import java.awt.Window;
+import java.text.NumberFormat;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.Random;
+import java.util.StringTokenizer;
+
+import javax.imageio.ImageIO;
+import javax.swing.AbstractButton;
+import javax.swing.ImageIcon;
+import javax.swing.JDialog;
+import javax.swing.JFrame;
+import javax.swing.JInternalFrame;
+import javax.swing.JLabel;
+import javax.swing.JScrollPane;
+import javax.swing.JTree;
+import javax.swing.tree.TreeNode;
+import javax.swing.tree.TreePath;
+
+import org.apache.log4j.Logger;
+
+import schmitzm.lang.LangUtil;
+import schmitzm.lang.ResourceProvider;
+
+/**
+ * Diese Klasse beinhaltet statische Hilfsfunktionen fuer das Arbeiten
+ * mit Swing-GUIs.
+ *
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
+ *
+ * @version 1.1
+ */
+public class SwingUtil {
+  private static final Logger LOGGER = Logger.getLogger( SwingUtil.class.getClass().getName() );
+
+  /**
+	 * {@link ResourceProvider}, der die Lokalisation fuer GUI-Komponenten des
+	 * Package {@code schmitzm.swing} zur Verfuegung stellt. Diese sind in
+	 * properties-Dateien unter {@code schmitzm.swing.resource.locales}
+	 * hinterlegt.
+	 */
+	public static ResourceProvider RESOURCE = new ResourceProvider(LangUtil
+			.extendPackagePath(SwingUtil.class,
+					"resource.locales.SwingResourceBundle"), Locale.ENGLISH);
+
+	/**
+	 * Convenience method to access the translation resources.
+	*/
+	public static String R(String key, Object... values) {
+		return RESOURCE.getString(key, values);
+	}
+
+  //****************************************************************************
+  // Diese Icons sind auf Basis der Icons von Gimp erstellt
+  // Eine Sammlung aller Gimp-Icons liegt im svn: gimp-tool-cursors.xcf
+  //****************************************************************************
+  /** Cursor in Form einer Lupe mit Plus Symbol */
+  public static final Cursor ZOOMIN_CURSOR = 	createCursorFromResourcePath("resource/cursor/zoom_in.gif",8,8,null);
+  /** Cursor in Form einer Lupe mit Minus Symbol */
+  public static final Cursor ZOOMOUT_CURSOR = 	createCursorFromResourcePath("resource/cursor/zoom_out.gif",8,8,null);
+  /** Cursor in Form einer Lupe ohne Symbol*/
+  public static final Cursor ZOOM_CURSOR = 		createCursorFromResourcePath("resource/cursor/zoom.gif",8,8,null);
+  /** Cursor in Form einer offenen Hand **/
+  public static final Cursor PAN_CURSOR = 		createCursorFromResourcePath("resource/cursor/hand_pan.png",9,11,null);
+  /** Cursor in Form einer geschlossenen Hand **/
+  public static final Cursor PANNING_CURSOR = 	createCursorFromResourcePath("resource/cursor/hand_closed.png",9,11,null);
+  /** Cursor in Form einer geschlossenen Hand **/
+  public static final Cursor CROSSHAIR_CURSOR = createCursorFromResourcePath("resource/cursor/crosshair.gif",10,10,null);
+
+//  public static final ImageIcon ICON_RASTER = createImageIconFromResourcePath("resource/icon/small/raster.png","");
+//  public static final ImageIcon ICON_VECTOR = createImageIconFromResourcePath("resource/icon/small/vector.png","");
+
+
+  /** Modus "Innen".
+   *  @see #setRelativeFramePosition(Window,Window,int,int) */
+  public static final int BOUNDS_INNER = 10;
+  /** Modus "Aussen".
+   *  @see #setRelativeFramePosition(Window,Window,int,int) */
+  public static final int BOUNDS_OUTER = 20;
+  /** Ausrichtung oben-mitte. */
+  public static final int NORTH = GridBagConstraints.NORTH;
+  /** Ausrichtung oben-links. */
+  public static final int NORTHWEST = GridBagConstraints.NORTHWEST;
+  /** Ausrichtung oben-rechts. */
+  public static final int NORTHEAST = GridBagConstraints.NORTHEAST;
+  /** Ausrichtung unten-mitte. */
+  public static final int SOUTH = GridBagConstraints.SOUTH;
+  /** Ausrichtung unten-links. */
+  public static final int SOUTHWEST = GridBagConstraints.SOUTHWEST;
+  /** Ausrichtung unten-rechts. */
+  public static final int SOUTHEAST = GridBagConstraints.SOUTHEAST;
+  /** Ausrichtung zentriert. */
+  public static final int CENTER = GridBagConstraints.CENTER;
+  /** Ausrichtung mitte-links. */
+  public static final int WEST = GridBagConstraints.WEST;
+  /** Ausrichtung mitte-rechts. */
+  public static final int EAST = GridBagConstraints.EAST;
+
+  /**
+   * Erzeugt ein Icon auf Basis einer relativen Pfad-Angabe. Als Basis-Verzeichnis
+   * wird der Classpath von {@code SwingUtil} verwendet.
+   * @param imgPath relativer Pfad des Icons
+   * @param imgDesc Beschreibung fuer Icon
+   * @return {@code null}, wenn das Icon nicht gefunden wird
+   */
+  public static ImageIcon createImageIconFromResourcePath(String imgPath, String imgDesc) {
+    return createImageIconFromResourcePath(null,imgPath,imgDesc);
+  }
+
+  /**
+   * Erzeugt ein Icon  auf Basis einer relativen Pfad-Angabe.
+   * @param resourceBase Klasse, deren Classpath als Basis-Verzeichnis verwendet wird
+   * @param imgPath relativer Pfad des Icons
+   * @param imgDesc Beschreibung fuer Icon
+   * @return {@code null}, wenn das Icon nicht gefunden wird
+   */
+  public static ImageIcon createImageIconFromResourcePath(Class resourceBase, String imgPath, String imgDesc) {
+    if ( resourceBase == null )
+      resourceBase = SwingUtil.class;
+    java.net.URL imgURL = resourceBase.getResource(imgPath);
+    if (imgURL == null) {
+      LOGGER.error("Couldn't find image file: " + imgPath);
+      return null;
+    }
+    return new ImageIcon(imgURL, imgDesc);
+  }
+
+  /**
+   * Erzeugt einen {@link Cursor} auf Basis einer relativen Pfad-Angabe.
+   * Als Basis-Verzeichnis wird der Classpath von {@code SwingUtil} verwendet.
+   * @param imgPath relativer Pfad des Icons
+   * @param x       X-Position im Image, die den Hotspot des Cursors darstellen soll
+   * @param y       Y-Position im Image, die den Hotspot des Cursors darstellen soll
+   * @param name    Bezeichnung fuer den Cursor
+   * @return {@code null}, wenn das Icon nicht gefunden wird
+   */
+  public static Cursor createCursorFromResourcePath(String imgPath, int x, int y, String name) {
+    java.net.URL imgURL = SwingUtil.class.getResource(imgPath);
+    try {
+      return Toolkit.getDefaultToolkit().createCustomCursor(
+          ImageIO.read(imgURL),
+          new Point(x, y),
+          name
+      );
+    } catch( Exception err ) {
+      return null;
+    }
+  }
+
+  /**
+   * Erzeugt ein neues Fenster mit {@link BorderLayout} und zeigt darin
+   * eine {@link Component} an.
+   * @param comp anzuzeigende Komponente (kann {@code null} sein)
+   * @param title Titel des Fensters (kann {@code null} sein)
+   * @param icon Icon-Image (kann {@code null} sein)
+   */
+  public static JFrame createFrame(Component comp, String title, Image icon) {
+    JFrame frame = new JFrame( title );
+    frame.getContentPane().setLayout( new BorderLayout() );
+    if ( comp != null )
+      frame.getContentPane().add( comp, BorderLayout.CENTER );
+    if ( title != null )
+      frame.setTitle( title );
+    if ( icon != null )
+      frame.setIconImage( icon );
+    frame.pack();
+    return frame;
+  }
+
+  /**
+   * Zeigt ein neues Fenster einer {@link Component} an.
+   * @param comp anzuzeigende Komponente (kann {@code null} sein)
+   * @param title Titel des Fensters (kann {@code null} sein)
+   * @param icon Icon-Image (kann {@code null} sein)
+   * @see #createFrame(Component, String, Image)
+   */
+  public static JFrame showFrame(Component comp, String title, Image icon) {
+    JFrame frame = createFrame(comp,title,icon);
+    frame.setVisible( true );
+    return frame;
+  }
+
+  /**
+	 * Liefert das Fenster, das eine GUI-Komponente beinhaltet. Wenn
+	 * GUI-Komponente selber ein {@link Window} ist, wird diese zurückgelifert.
+	 * 
+	 * @param comp
+	 *            eine GUI-Komponente
+	 * @return <code>null</code> falls die Komponente in keinem Fenster
+	 *         enthalten ist
+	 */
+	public static Window getParentWindow(Component comp) {
+		// durch die Parents laufen, bis Window gefunden
+		while (comp != null && !(comp instanceof Window))
+			comp = comp.getParent();
+		// wenn kein Window gefunden -> null zurueckgeben
+		if (comp == null)
+			return null;
+		return (Window) comp;
+	}
+
+  /**
+   * Liefert den {@link Frame}, das eine Kompoenente beinhaltet.
+   * @param comp eine GUI-Komponente
+   * @return <code>null</code> falls die Komponente in keinem {@link Frame}
+   *         enthalten ist
+   */
+  public static Frame getParentFrame(Component comp) {
+    // durch die Parents laufen, bis Frame gefunden
+    while ( comp!=null && !(comp instanceof Frame) )
+      comp = comp.getParent();
+    // wenn kein Frame gefunden -> null zurueckgeben
+    if ( comp== null )
+      return null;
+    return (Frame)comp;
+  }
+
+  /**
+   * Liefert das Fenster, das eine Kompoenente beinhaltet. Dabei kann es sich
+   * auch um einen {@link JInternalFrame} handelt.
+   * @param comp eine GUI-Komponente
+   * @return <code>null</code> falls die Komponente in keinem Fenster
+   *         enthalten ist
+   */
+  public static Component getParentWindowComponent(Component comp) {
+    // durch die Parents laufen, bis Window gefunden
+    while ( comp!=null && !(comp instanceof Window) && !(comp instanceof JInternalFrame))
+      comp = comp.getParent();
+    // wenn kein Window gefunden -> null zurueckgeben
+    if ( comp== null )
+      return null;
+    return comp;
+  }
+
+  /**
+   * Packt das Fenster, in dem eine Kompoenente plaziert ist.
+   * @param comp eine GUI-Komponente
+   * @return <code>false</code> falls die Komponente in keinem Fenster
+   *         enthalten ist
+   * @see Window#pack()
+   */
+  public static boolean packParentWindow(Component comp) {
+    Window w = getParentWindow(comp);
+    if ( w == null )
+      return false;
+    w.pack();
+    return true;
+  }
+
+  /**
+   * Prueft, ob eine Komponente eine Kind-Komponente einer anderen Komponente ist.
+   * @param child Component
+   * @param parent Component
+   * @return {@code false} wenn {@code child == null}, {@code true} wenn {@code child == parent},
+   *         {@code isChildComponent(child.getParent(),parent)} sonst
+   */
+  public static boolean isChildComponent(Component child, Component parent) {
+    if ( child == null )
+      return false;
+    if ( child == parent )
+      return true;
+    return isChildComponent(child.getParent(),parent);
+  }
+
+  /**
+   * Zentriert ein Fenster auf dem Monitor.
+   * @param window das zu zentrierende Fenster
+   */
+  public static void centerFrameOnScreen(Component comp) {
+      setRelativeFramePosition(comp,0.5,0.5);
+  }
+
+  /**
+   * Zentriert ein Fenster auf dem Monitor.<br>
+   * <b>Bemerkung:</b> Da {@link Window} eine {@link Component} ist, ist diese
+   * Methode eigentlich ueberfluessig. Es koennte {@link #centerFrameOnScreen(Component)}
+   * verwendet werden. Merkwuerdigerweise macht XULU beim Starten von der Console
+   * aus aber Probleme, wenn die Methode {@code centerFrameOnScreen(Window)} fehlt!!
+   * TODO: Probleme beim Xulu-Start loesen.
+   * @param window das zu zentrierende Fenster
+   */
+  public static void centerFrameOnScreen(Window comp) {
+      setRelativeFramePosition(comp,0.5,0.5);
+  }
+
+  /**
+   * Zentriert ein Fenster auf dem Monitor, aber verrückt das Window per Zufall um 10 Prozenz
+   *
+   * @param comp Eine Componente des zu zentrierenden Fensters. Wenn comp kein {@link Window} ist, wird das Parent {@link Window} ermittelt.
+   *
+   * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
+   */
+  public static void centerFrameOnScreenRandom(Component comp) {
+	  Random r = new Random();
+      setRelativeFramePosition(comp,0.5 + (r.nextDouble()*0.2-0.1) , 0.5 + (r.nextDouble()*0.2-0.1));
+  }
+
+
+  /**
+   * Positioniert ein Fenster auf dem Monitor, relativ zu dessen Groesse. (0.5/0.5)
+   * positioniert das Fenster z.B. genau in der Mitte des Monitors; (0.25/0.5)
+   * setzt das Fenster vertikal in die Mitte und horizontal auf ein Viertel der
+   * Monitorbreite.
+   * @param comp Eine Komponente des zu positionierenden Fensters oder direckt das {@link Window}. 
+   * @param relX  Relationsfaktor fuer die horizontale Position (0 < <code>relX</code> < 1)
+   * @param relY  Relationsfaktor fuer die vertikale Position (0 < <code>relX</code> < 1)
+   */
+  public static void setRelativeFramePosition(Component comp, double relX, double relY) {
+	  
+      setRelativeFramePosition(comp,null,relX,relY);
+  }
+
+  /**
+   * Positioniert ein Fenster auf dem Monitor relativ zur Position eines
+   * anderen Fensters. (0.5/0.5) positioniert das Fenster z.B. genau in der Mitte
+   * anderen Fensters. (0.25/0.5) setzt das Fenster vertikal in die Mitte und
+   * horizontal auf ein Viertel des Referenz-Fensters.
+   * @param comp Eine Komponente des zu positionierenden Fensters oder direkt das {@link Window}.
+   * @param relFrame Fenster zu dem das Fenster in Relation gesetzt wird (wenn
+   *                 <code>null</code> wird der gesamte Monitor verwendet)
+   * @param relX  Relationsfaktor fuer die horizontale Position (0 < <code>relX</code> < 1)
+   * @param relY  Relationsfaktor fuer die vertikale Position (0 < <code>relY</code> < 1)
+   */
+  public static void setRelativeFramePosition(Component comp, Window relFrame, double relX, double relY) {
+	 
+	  // Added by SK, 17.4.2009
+	  // sk.sc
+	  Window window;
+	  if (comp instanceof Window){
+		  window = (Window) comp;
+	  } else {
+		  window = SwingUtil.getParentWindow(comp);
+	  }
+	  // sk.ec
+	  
+      Dimension screenSize  = Toolkit.getDefaultToolkit().getScreenSize();
+      Dimension relSize     = (relFrame==null) ? screenSize : relFrame.getSize();
+      Point     relLocation = (relFrame==null) ? new Point(0,0) : relFrame.getLocation();
+
+      // Fenster auf Monitor-Groesse anpassen
+      Dimension frameSize = window.getSize();
+      if (frameSize.height > screenSize.height) {
+        frameSize.height = screenSize.height;
+      }
+      if (frameSize.width > screenSize.width) {
+        frameSize.width = screenSize.width;
+      }
+      // Fenster positionieren
+      window.setLocation( relLocation.x + Math.round( (relSize.width-frameSize.width)*(float)relX ),
+                         relLocation.y + Math.round( (relSize.height-frameSize.height)*(float)relY )
+      );
+  }
+
+  /**
+   * Positioniert ein Fenster auf dem Monitor relativ zur Position eines
+   * anderen Fensters. Das Fenster wird jedoch immer innerhalb des Bildschirms
+   * positioniert.
+   * @param window das zu positionierende Fenster
+   * @param relWindow Fenster zu dem das Fenster in Relation gesetzt wird (wenn
+   *                 <code>null</code> wird der gesamte Monitor verwendet)
+   * @param type bestimmt, ob das Fenster innerhalb oder ausserhalb des relativen
+   *                       Fensters positioniert wird ({@link #BOUNDS_INNER} oder {@link #BOUNDS_OUTER}).
+   * @param position Positionierung des Fensters ({@link #NORTH}, {@link #NORTHEAST}, ...)
+   */
+  public static void setRelativeFramePosition(Window window, Window relWindow, int type, int position) {
+    if ( type == BOUNDS_INNER ) {
+      // An den inneren Grenzen des Frames ausrichten
+      double relX = 0;
+      double relY = 0;
+      switch ( position ) {
+        case NORTH:     relX = 0.5; relY = 0.0; break;
+        case NORTHWEST: relX = 0.0; relY = 0.0; break;
+        case NORTHEAST: relX = 1.0; relY = 0.0; break;
+        case SOUTH:     relX = 0.5; relY = 1.0; break;
+        case SOUTHWEST: relX = 0.0; relY = 1.0; break;
+        case SOUTHEAST: relX = 1.0; relY = 1.0; break;
+        case CENTER:    relX = 0.5; relY = 0.5; break;
+        case WEST:      relX = 0.0; relY = 0.5; break;
+        case EAST:      relX = 1.0; relY = 0.5; break;
+        default: throw new IllegalArgumentException("Unsupported mode for 'position'.");
+      }
+      setRelativeFramePosition(window,relWindow,relX,relY);
+      return;
+    }
+    if ( type == BOUNDS_OUTER ) {
+      Dimension screenSize  = Toolkit.getDefaultToolkit().getScreenSize();
+      Dimension relSize     = (relWindow==null) ? screenSize : relWindow.getSize();
+      Point     relLocation = (relWindow==null) ? new Point(0,0) : relWindow.getLocation();
+      // An den Aussen-Grenzen des Frames ausrichten
+      Point    loc = new Point(0,0);
+      switch ( position ) {
+        case NORTH:
+        case NORTHWEST:
+        case NORTHEAST: loc.y = relLocation.y - window.getHeight(); break;
+        case SOUTH:
+        case SOUTHWEST:
+        case SOUTHEAST: loc.y = relLocation.y + relSize.height; break;
+        case CENTER:
+        case WEST:
+        case EAST:      loc.y = relLocation.y + relSize.height/2 - window.getHeight()/2; break;
+        default: throw new IllegalArgumentException("Unsupported mode for 'position'.");
+      }
+      switch ( position ) {
+        case WEST:
+        case NORTHWEST:
+        case SOUTHWEST: loc.x = relLocation.x - window.getWidth(); break;
+        case EAST:
+        case NORTHEAST:
+        case SOUTHEAST: loc.x = relLocation.x + relSize.width; break;
+        case CENTER:
+        case NORTH:
+        case SOUTH:     loc.x = relLocation.x + relSize.width/2 - window.getWidth()/2; break;
+        default: throw new IllegalArgumentException("Unsupported mode for 'position'. GridBagConstraints location expected!");
+      }
+
+      loc.x = Math.max(0,loc.x);
+      loc.y = Math.max(0,loc.y);
+      if ( loc.x + window.getWidth() > screenSize.width )
+        loc.x = screenSize.width - window.getWidth();
+      if ( loc.y + window.getHeight() > screenSize.height )
+        loc.y = screenSize.height - window.getHeight();
+
+      // Fenster positionieren
+      window.setLocation( loc );
+      return;
+    }
+    throw new IllegalArgumentException("Unsupported mode for 'type'. BOUNDS_INNER or BOUNDS_OUTER expected!");
+  }
+
+  /**
+   * Aendert die Breite einer GUI-Komponente.
+   * @param comp GUI-Komponente
+   * @param w    Breite
+   */
+  public static void setWidth(Component comp, int w) {
+    Dimension d = comp.getPreferredSize();
+    d.width = w;
+    comp.setSize(d);
+  }
+
+  /**
+   * Aendert die Hoehe einer GUI-Komponente.
+   * @param comp GUI-Komponente
+   * @param h    Hoehe
+   */
+  public static void setHeight(Component comp, int h) {
+    Dimension d = comp.getPreferredSize();
+    d.height = h;
+    comp.setSize(d);
+  }
+
+  /**
+   * Aendert die bevorzugte Breite einer GUI-Komponente.
+   * @param comp GUI-Komponente
+   * @param w    Breite
+   */
+  public static void setPreferredWidth(Component comp, int w) {
+    Dimension d = comp.getPreferredSize();
+    d.width = w;
+    comp.setPreferredSize(d);
+  }
+
+  /**
+   * Aendert die bevorzugte Hoehe einer GUI-Komponente.
+   * @param comp GUI-Komponente
+   * @param h    Hoehe
+   */
+  public static void setPreferredHeight(Component comp, int h) {
+    Dimension d = comp.getPreferredSize();
+    d.height = h;
+    comp.setPreferredSize(d);
+  }
+
+  /**
+   * Aendert die minimal erlaubte Breite einer GUI-Komponente.
+   * @param comp GUI-Komponente
+   * @param w    Breite
+   * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
+   */
+  public static void setMinimumWidth(Component comp, int w) {
+	  Dimension d = comp.getMinimumSize();
+	  d.width = w;
+	  comp.setMinimumSize(d);
+  }
+
+  /**
+   * Aendert die minimal erlaubte Hoehe einer GUI-Komponente.
+   * @param comp GUI-Komponente
+   * @param h    Hoehe
+   * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
+   */
+  public static void setMinimumHeight(Component comp, int h) {
+	  Dimension d = comp.getMinimumSize();
+	  d.height = h;
+	  comp.setMinimumSize(d);
+  }
+
+  /**
+   * Aendert die maximal erlaubte Breite einer GUI-Komponente.
+   * @param comp GUI-Komponente
+   * @param w    Breite
+   */
+  public static void setMaximumWidth(Component comp, int w) {
+    Dimension d = comp.getMaximumSize();
+    d.width = w;
+    comp.setMaximumSize(d);
+  }
+
+  /**
+   * Aendert die maximal erlaubte Hoehe einer GUI-Komponente.
+   * @param comp GUI-Komponente
+   * @param h    Hoehe
+   */
+  public static void setMaximumHeight(Component comp, int h) {
+    Dimension d = comp.getMaximumSize();
+    d.height = h;
+    comp.setMaximumSize(d);
+  }
+
+  /**
+   * Fixiert die Groesse einer GUI-Komponente.
+   * @param comp GUI-Komponente
+   * @param d Ausmasse (Hoehe und Breite)
+   */
+  public static void fixComponentSize(Component comp, Dimension d) {
+    comp.setPreferredSize(d);
+    comp.setMinimumSize(d);
+    comp.setMaximumSize(d);
+  }
+
+  /**
+   * Fixiert die Groesse einer GUI-Komponente mit der aktuell
+   * bevorzugten Groesse.
+   * @param comp GUI-Komponente
+   */
+  public static void fixComponentSize(Component comp) {
+    fixComponentSize(comp, comp.getPreferredSize());
+  }
+
+  /***
+   * Setzt die Hintergrundfarbe einer Komponente und aller darin enthaltener
+   * Komponenten.
+   * @param comp Komponente
+   * @param color neue Hintergrund-Farbe
+   */
+  public static void setAllBackground(Component comp, Color color) {
+    comp.setBackground( color );
+    if ( comp instanceof JFrame )
+      setAllBackground( ((JFrame)comp).getContentPane(), color );
+    if ( comp instanceof JScrollPane )
+      setAllBackground( ((JScrollPane)comp).getViewport(), color );
+    else if ( comp instanceof Container )
+      for ( Component innerComp : ((Container)comp).getComponents() )
+        setAllBackground( innerComp, color );
+  }
+
+  /**
+   * Versucht, aus einem String eine Farbe zu erstellen. Drei Moeglichekeiten
+   * gibt es fuer das Format des Strings:
+   * <ol>
+   *   <li><code>"RGB(<i>red</i>,<i>green</i>,<i>blue</i>)"</code><br>
+   *       wobei <i>red</i>,<i>green</i> und <i>blue</i> dezimale Werte
+   *       zwischen 0 und 255 sind.</li>
+   *   <li>Der String stellt einen Integer-Wert im dezimalen, oktalen oder
+   *       hexadezimalen Format dar, aus dem die 3 RGB-Werte extrahiert werden
+   *       (siehe {@link Color#decode(String) Color.decode(..)}).</li>
+   *   <li>Der String spezifiziert ein statisches Feld der Klasse {@link Color}.<br>
+   *       z.B. steht <code>"RED"</code> fuer {@link Color#RED Color.RED},
+   *            <code>"darkGray"</code> fuer {@link Color#darkGray Color.darkGray} oder
+   *            <code>"LIGHT_GRAY"</code> fuer {@link Color#LIGHT_GRAY Color.LIGHT_GRAY}</li>
+   * </ol>
+   *
+   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+   *
+   * @throws IllegalArgumentException wenn der uebergebene String nicht interpretiert werden kann.
+   *
+   */
+  // Schmeisst nur noch IllegalArgumentException, vorher Exception. (SK) 21.08.2007
+  public static Color parseColor(String colorStr) throws IllegalArgumentException {
+    // Wenn String mit "RGB(" startet, Format RGB(<r>,<b>,<g>) parsen
+    if ( colorStr.toUpperCase().startsWith("RGB(") )
+      try {
+        StringTokenizer tok = new StringTokenizer(colorStr.substring(4));
+        int r = Integer.parseInt(tok.nextToken(",()\n"));
+        int g = Integer.parseInt(tok.nextToken(",()\n"));
+        int b = Integer.parseInt(tok.nextToken(",()\n"));
+        return new Color(r,g,b);
+      } catch (Exception err) {
+        throw new IllegalArgumentException("Invalid RGB-specification. RGB(<r>,<g>,<b>) expected.",err);
+      }
+
+    // Versucht, die Farbe als dezimalen, oktalen oder hexadezimalen Integer
+    // einzulesen
+    Long testLong = null;
+    try {
+      testLong = Long.decode(colorStr);
+      return Color.decode(colorStr);
+    } catch (NumberFormatException err) {
+      // wenn 'testLong' ein gueltiger Long ist, handelt es sich zwar um
+      // eine gueltige Zahl, aber kein passendes Integer-Format nicht!
+      if ( testLong != null )
+        throw new IllegalArgumentException(colorStr + " is not a valid RGB-Integer in decimal, octal or hexadecimal format.");
+    }
+
+    // Wenn auch kein Integer angegeben wurde, wird versucht, die Farbe
+    // als Feld von java.awt.Color zu interpretieren
+    try {
+      return (Color)Color.class.getDeclaredField(colorStr).get(null);
+    } catch ( Exception err1 ) {
+      try {
+        // als letztes noch versuchen, die Farbe in Gross-Buchstaben zu finden
+        return (Color) Color.class.getDeclaredField(colorStr.toUpperCase()).get(null);
+      } catch ( Exception err2 ) {
+        throw new IllegalArgumentException(colorStr + " is not a valid color name. Name of a static field of class java.awt.Color expected.");
+      }
+    }
+  }
+
+  /**
+   * Setzt das Label eine Componente neu. Macht nichts, falls {@code newLabel}
+   * oder {@code comp} den Wert {@code null} hat.
+   * @param comp {@link JLabel}, {@link AbstractButton}, {@link JDialog} oder
+   *             {@link Frame}
+   * @param newLabel neue Beschriftung
+   * @exception UnsupportedOperationException falls {@code comp} nicht
+   *            unterstuetzt wird.
+   *
+   */
+  public static void resetCaption(Component comp, Object newLabel) {
+    if ( comp == null || newLabel == null )
+      return;
+    if ( comp instanceof JLabel )
+      ((JLabel)comp).setText( newLabel.toString() );
+    else if ( comp instanceof AbstractButton )
+      ((AbstractButton)comp).setText( newLabel.toString() );
+    else if ( comp instanceof Frame )
+      ((Frame)comp).setTitle( newLabel.toString() );
+    else if ( comp instanceof JDialog )
+      ((JDialog)comp).setTitle( newLabel.toString() );
+    else
+      throw new UnsupportedOperationException(SwingUtil.class.getSimpleName()+"resetCaption(.) can not be applied to "+comp.getClass().getSimpleName());
+  }
+
+  /**
+   * Erstellt das Pattern fuer ein {@link NumberFormat}.
+   * @param sample Beispiel-Wert, der die Anzahl der dargestellten Nachkomma-Stellen
+   *               bestimmt
+   */
+  public static String getNumberFormatPattern(double sample) {
+    String format = "0";
+    for (int i=0; sample != (int)sample; i++ ) {
+      if ( i==0 )
+        format += ".";
+      sample *= 10;
+      format += "0";
+    }
+    return format;
+  }
+
+  /**
+   * Erstellt das Pattern fuer ein {@link NumberFormat}.
+   * @param digits Anzahl der dargestellten Nachkomma-Stellen
+   */
+  public static String getNumberFormatPattern(int digits) {
+    String format = "0";
+    for (int i=0; i<digits; i++ ) {
+      if ( i==0 )
+        format += ".";
+      format += "0";
+    }
+    return format;
+  }
+
+  /**
+   * Copied from http://www.exampledepot.com/egs/javax.swing.tree/ExpandAll.html
+   * e1029. Expanding or Collapsing All Nodes in a JTree Component
+   * If expand is true, expands all nodes in the tree.
+   * Otherwise, collapses all nodes in the tree.
+   * @param tree {@link JTree} to expand or collapse
+   */
+  public static void expandAll(JTree tree, boolean expand) {
+      TreeNode root = (TreeNode)tree.getModel().getRoot();
+
+      // Traverse tree from root
+      expandAll(tree, new TreePath(root), expand);
+  }
+  private static void expandAll(JTree tree, TreePath parent, boolean expand) {
+      // Traverse children
+      TreeNode node = (TreeNode)parent.getLastPathComponent();
+      if (node.getChildCount() >= 0) {
+          for (Enumeration e=node.children(); e.hasMoreElements(); ) {
+              TreeNode n = (TreeNode)e.nextElement();
+              TreePath path = parent.pathByAddingChild(n);
+              expandAll(tree, path, expand);
+          }
+      }
+
+      // Expansion or collapse must be done bottom-up
+      if (expand) {
+          tree.expandPath(parent);
+      } else {
+          tree.collapsePath(parent);
+      }
+  }
+
+  /**
+   * This method maximizes a frame; the iconified bit is not affected
+   * Taken from e564. Iconifying and Maximizing a Frame,
+   * http://www.exampledepot.com/egs/java.awt/frame_FrameIconify.html
+   *
+   * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
+   */
+  public static void maximize(Frame frame) {
+      int state = frame.getExtendedState();
+
+      // Set the maximized bits
+      state |= Frame.MAXIMIZED_BOTH;
+
+      // Maximize the frame
+      frame.setExtendedState(state);
+  }
+
+}

Modified: trunk/src/schmitzm/swing/SwingWorker.java
===================================================================
--- trunk/src/schmitzm/swing/SwingWorker.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/SwingWorker.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,245 +1,263 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing;
-
-import java.awt.Frame;
-
-import schmitzm.lang.WorkingThread;
-
-/**
- * Diese Klasse stellt einen Thread dar, der (aufwendigere) Arbeiten innerhalb einer
- * GUI ausfuehrt, damit diese nicht blockiert.<br>
- * Dem SwingWorker <b>kann</b> ein {@link StatusDialog} (modal!) zugeordnet werden.
- * Ist dies der Fall kehrt der Thread nicht aus seiner <code>start()</code>-Routine
- * zurueck sondern sperrt mit dem Dialog die zugrunde liegende GUI.
- * Ist die "Arbeit" beendet schliesst der Thread automatisch den Dialog, so dass
- * die GUI wieder zugeaenglich wird. Zudem kann die Arbeit des SwingWorker jederzeit
- * ueber den Abbruch-Button des {@link StatusDialog} beendet werden.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class SwingWorker extends WorkingThread {
-  /** Speichert den Arbeitsablauf fuer den Thread. */
-  protected Work         work = null;
-  /** Speichert den Dialog, der waehrend der Arbeit des SwingWorkers angezeigt wird. */
-  protected StatusDialog dialog = null;
-  /** Speichert, ob der Dialog nach Beendigung der Arbeit offen gehalten soll
-   *  (Default: <code>false</code>).
-   *  @see #setKeepOpen(boolean) */
-  protected boolean keepOpen = false;
-  /** Speichert, ob der Worker (durch einen Fehler) abgebrochen wurde ({@code true})
-   *  oder seine Arbeit erfolgreich ausgefuehrt hat ({@code false}). */
-  protected boolean canceled = false;
-  /** Resultat von {@link Work#execute()}. Kann nach Beendigung des Threads
-   *  ueber {@link #getWorkResult()} abgefragt werden.*/
-  protected Object workResult = null;
-
-  /**
-   * Erzeugt einen neuen SwingWorker. Waehrend der Arbeit wird kein Dialog
-   * angezeigt. Der Thread kehrt unmittelbar aus seiner <code>start()</code>-Routine
-   * zurueck, so dass eine untergeordnete GUI <b>nicht</b> blockiert.
-   * @param work auszufuehrende Arbeit
-   */
-  public SwingWorker(Work work) {
-    this(work,null);
-  }
-
-  /**
-   * Erzeugt einen neuen SwingWorker. Der Thread kehrt nicht aus seiner
-   * <code>start()</code>-Routine zurueck, sondern zeigt den (modalen) Dialog
-   * an, so dass eine untergeordnete GUI gesperrt wird.
-   * @param work   auszufuehrende Arbeit
-   * @param dialog anzuzeigender Dialog (modal!)
-   */
-  public SwingWorker(Work work, StatusDialog dialog) {
-    this.work   = work;
-    this.dialog = dialog;
-    // Worker in der Work-Klasse setzten, so dass waehrend der
-    // Ausfuehrung der Arbeit auf den Worker (Dialog) zugegriffen werden
-    // kann
-    work.worker = this;
-  }
-
-  /**
-   * Erzeugt einen neuen SwingWorker. Der Thread kehrt nicht aus seiner
-   * <code>start()</code>-Routine zurueck, sondern zeigt einen (modalen) Dialog
-   * an, so dass eine untergeordnete GUI gesperrt wird.
-   * @param work       auszufuehrende Arbeit
-   * @param parent     uebergeordnete GUI (kann <code>null</code> sein!)
-   * @param statusMess Meldung, die im Dialog angezeigt wird
-   */
-  public SwingWorker(Work work, Frame parent, String statusMess) {
-    this(work,parent,statusMess,0.5,0.5);
-  }
-
-  /**
-   * Erzeugt einen neuen SwingWorker. Der Thread kehrt nicht aus seiner
-   * <code>start()</code>-Routine zurueck, sondern zeigt einen (modalen) Dialog
-   * an, so dass eine untergeordnete GUI gesperrt wird.
-   * @param work       auszufuehrende Arbeit
-   * @param parent     uebergeordnete GUI (kann <code>null</code> sein!)
-   * @param statusMess Meldung, die im Dialog angezeigt wird
-   * @param relX       horizontale Positionierung des Dialogs relativ zum uebergeordneten Fenster
-   * @param relY       vertikale Positionierung des Dialogs relativ zum uebergeordneten Fenster
-   */
-  public SwingWorker(Work work, Frame parent, String statusMess, double relX, double relY) {
-    this(work,
-         new StatusDialog(
-           parent,
-           SwingUtil.RESOURCE.getString("WaitMess"),
-           statusMess,
-           relX,
-           relY
-         )
-    );
-  }
-
-  /**
-   * Bestimmt, ob der Dialog nach Beendigung der Arbeit geoeffnet bleibt.
-   * Standardmaessig wird der Dialog automatisch geschlossen.
-   * @param keepOpen wenn <code>false</code> wird der Dialog nach Beendigung
-   *                 der Arbeit automatisch geschlossen.
-   */
-  public void setKeepOpen(boolean keepOpen) {
-    this.keepOpen = keepOpen;
-  }
-
-  /**
-   * Prueft, ob der Dialog nach Beendigung der Arbeit geoeffnet bleibt.
-   * Standardmaessig wird der Dialog automatisch geschlossen.
-   * @see #setKeepOpen(boolean)
-   */
-  public boolean isKeptOpen() {
-    return this.keepOpen;
-  }
-
-  /**
-   * Startet den Thread. Wurde ein Dialog angegeben/erzeugt wird dieser
-   * nach dem Thread-Start angezeigt und blockiert den untergeordneten
-   * Ablauf. Der Thread kehrt erst nach Beendigung seiner Arbeit oder wenn
-   * der Dialog abgebrochen wurde, aus dieser Methode zurueck.
-   */
-  public void start() {
-    super.start();
-    if ( dialog != null ) {
-      dialog.setVisible(true);
-      if ( dialog.isCanceled() && isRunning() )
-        terminate();
-    }
-  }
-
-  /**
-   * Fuehrt die dem Thread zugeordnete Arbeit aus und verarbeitet auftretende
-   * Fehler.
-   * @see Work#execute()
-   * @see Work#performError(Throwable)
-   */
-  public void performWork() {
-    try {
-      this.canceled = false;
-      this.workResult = work.execute();
-    } catch (Throwable err) {
-      // Fehler die zum Abbruch der "Arbeit" fuehren
-      this.canceled = true;
-      this.workResult = null;
-      work.performError(err);
-    }
-  }
-
-  /**
-   * Initialisierung des Threads. Macht nichts!
-   */
-  public void performInit() {
-  }
-
-  /**
-   * Wird ausgefuehrt nachdem der Thread beendet wurde. Schliesst einen evt.
-   * vorhandenen Dialog, so dass eine untergeordnete GUI wieder freigegeben wird.
-   */
-  public void performDispose() {
-    if (dialog != null) {
-      if ( dialog.isCanceled() )
-        this.canceled = true;
-      if ( !keepOpen )
-        dialog.setVisible(false);
-      else
-        dialog.setDialogOption( StatusDialog.OK_OPTION );
-    }
-  }
-
-  /**
-   * Bricht die Arbeit des Threads <b>unmittelbar</b> und <b>unkontrolliert</b>
-   * ab.
-   * @see Thread#stop()
-   */
-  public void terminate() {
-    stop();
-  }
-
-  /**
-   * Liefert den Dialog, der waehrend der Arbeit des Threads angezeigt wird.
-   * @return <code>null</code> falls kein Dialog angegeben wurde.
-   */
-  public StatusDialog getDialog() {
-    return dialog;
-  }
-
-  /**
-   * Liefert {@code true}, wenn der Worker (aufgrund eines Fehlers oder
-   * manuell durch den Dialog) abgebrochen wurde.
-   */
-  public boolean isCanceled() {
-    return canceled;
-  }
-
-  /**
-   * Liefert nach der Beendigung des Threads dessen Ergebnis.
-   * @see Work#execute()
-   */
-  public Object getWorkResult() {
-    return this.workResult;
-  }
-
-  /**
-   * Diese Klasse spezifiziert die Arbeit eines {@link SwingWorker}.
-   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-   * @version 1.0
-   */
-  public static abstract class Work {
-    // speichert den SwingWorker, der die Arbeit verrichtet
-    // WIRD VON DER AUSFUEHRENDEN SWINGWORKER-KLASSE GESETZT!!
-    private SwingWorker worker = null;
-
-    /**
-     * Implementiert den Arbeitsablauf des {@link SwingWorker}.
-     * @return "irgendwas" als Ergebnis
-     */
-    public abstract Object execute() throws Exception;
-
-    /**
-     * Implementiert die Fehlerbehandlung, wenn waehrend des Arbeitsablauf
-     * ein Fehler auftritt. In dieser Basis-Implementierung wird lediglich
-     * eine Fehlermeldung angezeigt.<br>
-     * Kann gefahrlos von Unterklassen ueberschrieben werden.
-     */
-    public void performError(Throwable err) {
-      ExceptionDialog.show(worker.dialog,err);//,SwingResource.DEFAULT.getString("Error"),err.getMessage());
-    };
-
-    /**
-     * Liefert den {@link SwingWorker}, der die Arbeit verrichtet.
-     */
-    public SwingWorker getSwingWorker() {
-      return worker;
-    }
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
+
+import java.awt.Frame;
+
+import schmitzm.lang.WorkingThread;
+
+/**
+ * Diese Klasse stellt einen Thread dar, der (aufwendigere) Arbeiten innerhalb einer
+ * GUI ausfuehrt, damit diese nicht blockiert.<br>
+ * Dem SwingWorker <b>kann</b> ein {@link StatusDialog} (modal!) zugeordnet werden.
+ * Ist dies der Fall kehrt der Thread nicht aus seiner <code>start()</code>-Routine
+ * zurueck sondern sperrt mit dem Dialog die zugrunde liegende GUI.
+ * Ist die "Arbeit" beendet schliesst der Thread automatisch den Dialog, so dass
+ * die GUI wieder zugeaenglich wird. Zudem kann die Arbeit des SwingWorker jederzeit
+ * ueber den Abbruch-Button des {@link StatusDialog} beendet werden.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class SwingWorker extends WorkingThread {
+  /** Speichert den Arbeitsablauf fuer den Thread. */
+  protected Work         work = null;
+  /** Speichert den Dialog, der waehrend der Arbeit des SwingWorkers angezeigt wird. */
+  protected StatusDialog dialog = null;
+  /** Speichert, ob der Dialog nach Beendigung der Arbeit offen gehalten soll
+   *  (Default: <code>false</code>).
+   *  @see #setKeepOpen(boolean) */
+  protected boolean keepOpen = false;
+  /** Speichert, ob der Worker (durch einen Fehler) abgebrochen wurde ({@code true})
+   *  oder seine Arbeit erfolgreich ausgefuehrt hat ({@code false}). */
+  protected boolean canceled = false;
+  /** Resultat von {@link Work#execute()}. Kann nach Beendigung des Threads
+   *  ueber {@link #getWorkResult()} abgefragt werden.*/
+  protected Object workResult = null;
+
+  /**
+   * Erzeugt einen neuen SwingWorker. Waehrend der Arbeit wird kein Dialog
+   * angezeigt. Der Thread kehrt unmittelbar aus seiner <code>start()</code>-Routine
+   * zurueck, so dass eine untergeordnete GUI <b>nicht</b> blockiert.
+   * @param work auszufuehrende Arbeit
+   */
+  public SwingWorker(Work work) {
+    this(work,null);
+  }
+
+  /**
+   * Erzeugt einen neuen SwingWorker. Der Thread kehrt nicht aus seiner
+   * <code>start()</code>-Routine zurueck, sondern zeigt den (modalen) Dialog
+   * an, so dass eine untergeordnete GUI gesperrt wird.
+   * @param work   auszufuehrende Arbeit
+   * @param dialog anzuzeigender Dialog (modal!)
+   */
+  public SwingWorker(Work work, StatusDialog dialog) {
+    this.work   = work;
+    this.dialog = dialog;
+    // Worker in der Work-Klasse setzten, so dass waehrend der
+    // Ausfuehrung der Arbeit auf den Worker (Dialog) zugegriffen werden
+    // kann
+    work.worker = this;
+  }
+
+  /**
+   * Erzeugt einen neuen SwingWorker. Der Thread kehrt nicht aus seiner
+   * <code>start()</code>-Routine zurueck, sondern zeigt einen (modalen) Dialog
+   * an, so dass eine untergeordnete GUI gesperrt wird.
+   * @param work       auszufuehrende Arbeit
+   * @param parent     uebergeordnete GUI (kann <code>null</code> sein!)
+   * @param statusMess Meldung, die im Dialog angezeigt wird
+   */
+  public SwingWorker(Work work, Frame parent, String statusMess) {
+    this(work,parent,statusMess,0.5,0.5);
+  }
+
+  /**
+   * Erzeugt einen neuen SwingWorker. Der Thread kehrt nicht aus seiner
+   * <code>start()</code>-Routine zurueck, sondern zeigt einen (modalen) Dialog
+   * an, so dass eine untergeordnete GUI gesperrt wird.
+   * @param work       auszufuehrende Arbeit
+   * @param parent     uebergeordnete GUI (kann <code>null</code> sein!)
+   * @param statusMess Meldung, die im Dialog angezeigt wird
+   * @param relX       horizontale Positionierung des Dialogs relativ zum uebergeordneten Fenster
+   * @param relY       vertikale Positionierung des Dialogs relativ zum uebergeordneten Fenster
+   */
+  public SwingWorker(Work work, Frame parent, String statusMess, double relX, double relY) {
+    this(work,
+         new StatusDialog(
+           parent,
+           SwingUtil.RESOURCE.getString("WaitMess"),
+           statusMess,
+           relX,
+           relY
+         )
+    );
+  }
+
+  /**
+   * Bestimmt, ob der Dialog nach Beendigung der Arbeit geoeffnet bleibt.
+   * Standardmaessig wird der Dialog automatisch geschlossen.
+   * @param keepOpen wenn <code>false</code> wird der Dialog nach Beendigung
+   *                 der Arbeit automatisch geschlossen.
+   */
+  public void setKeepOpen(boolean keepOpen) {
+    this.keepOpen = keepOpen;
+  }
+
+  /**
+   * Prueft, ob der Dialog nach Beendigung der Arbeit geoeffnet bleibt.
+   * Standardmaessig wird der Dialog automatisch geschlossen.
+   * @see #setKeepOpen(boolean)
+   */
+  public boolean isKeptOpen() {
+    return this.keepOpen;
+  }
+
+  /**
+   * Startet den Thread. Wurde ein Dialog angegeben/erzeugt wird dieser
+   * nach dem Thread-Start angezeigt und blockiert den untergeordneten
+   * Ablauf. Der Thread kehrt erst nach Beendigung seiner Arbeit oder wenn
+   * der Dialog abgebrochen wurde, aus dieser Methode zurueck.
+   */
+  public void start() {
+    super.start();
+    if ( dialog != null ) {
+      dialog.setVisible(true);
+      if ( dialog.isCanceled() && isRunning() )
+        terminate();
+    }
+  }
+
+  /**
+   * Fuehrt die dem Thread zugeordnete Arbeit aus und verarbeitet auftretende
+   * Fehler.
+   * @see Work#execute()
+   * @see Work#performError(Throwable)
+   */
+  public void performWork() {
+    try {
+      this.canceled = false;
+      this.workResult = work.execute();
+    } catch (Throwable err) {
+      // Fehler die zum Abbruch der "Arbeit" fuehren
+      this.canceled = true;
+      this.workResult = null;
+      work.performError(err);
+    }
+  }
+
+  /**
+   * Initialisierung des Threads. Macht nichts!
+   */
+  public void performInit() {
+  }
+
+  /**
+   * Wird ausgefuehrt nachdem der Thread beendet wurde. Schliesst einen evt.
+   * vorhandenen Dialog, so dass eine untergeordnete GUI wieder freigegeben wird.
+   */
+  public void performDispose() {
+    if (dialog != null) {
+      if ( dialog.isCanceled() )
+        this.canceled = true;
+      if ( !keepOpen )
+        dialog.setVisible(false);
+      else
+        dialog.setDialogOption( StatusDialog.OK_OPTION );
+    }
+  }
+
+  /**
+   * Bricht die Arbeit des Threads <b>unmittelbar</b> und <b>unkontrolliert</b>
+   * ab.
+   * @see Thread#stop()
+   */
+  public void terminate() {
+    stop();
+  }
+
+  /**
+   * Liefert den Dialog, der waehrend der Arbeit des Threads angezeigt wird.
+   * @return <code>null</code> falls kein Dialog angegeben wurde.
+   */
+  public StatusDialog getDialog() {
+    return dialog;
+  }
+
+  /**
+   * Liefert {@code true}, wenn der Worker (aufgrund eines Fehlers oder
+   * manuell durch den Dialog) abgebrochen wurde.
+   */
+  public boolean isCanceled() {
+    return canceled;
+  }
+
+  /**
+   * Liefert nach der Beendigung des Threads dessen Ergebnis.
+   * @see Work#execute()
+   */
+  public Object getWorkResult() {
+    return this.workResult;
+  }
+
+  /**
+   * Diese Klasse spezifiziert die Arbeit eines {@link SwingWorker}.
+   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+   * @version 1.0
+   */
+  public static abstract class Work {
+    // speichert den SwingWorker, der die Arbeit verrichtet
+    // WIRD VON DER AUSFUEHRENDEN SWINGWORKER-KLASSE GESETZT!!
+    private SwingWorker worker = null;
+
+    /**
+     * Implementiert den Arbeitsablauf des {@link SwingWorker}.
+     * @return "irgendwas" als Ergebnis
+     */
+    public abstract Object execute() throws Exception;
+
+    /**
+     * Implementiert die Fehlerbehandlung, wenn waehrend des Arbeitsablauf
+     * ein Fehler auftritt. In dieser Basis-Implementierung wird lediglich
+     * eine Fehlermeldung angezeigt.<br>
+     * Kann gefahrlos von Unterklassen ueberschrieben werden.
+     */
+    public void performError(Throwable err) {
+      ExceptionDialog.show(worker.dialog,err);//,SwingResource.DEFAULT.getString("Error"),err.getMessage());
+    };
+
+    /**
+     * Liefert den {@link SwingWorker}, der die Arbeit verrichtet.
+     */
+    public SwingWorker getSwingWorker() {
+      return worker;
+    }
+  }
+}

Modified: trunk/src/schmitzm/swing/TextAreaPrintStream.java
===================================================================
--- trunk/src/schmitzm/swing/TextAreaPrintStream.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/TextAreaPrintStream.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,40 +1,58 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing;
-
 import java.io.OutputStream;
 import java.io.PrintStream;
 
 import javax.swing.JTextArea;
-
-/**
- * Diese Klasse stellt einen {@link PrintStream} dar, der an eine {@link JTextArea}
- * gekoppelt ist. Jegliche Ausgabe, die auf den Stream geschrieben wird, wird
- * in der TextArea ausgegeben
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class TextAreaPrintStream extends PrintStream {
-  /**
-   * Erzeugt einen neuen Stream.
-   * @param textArea Ausgabe-Komponente
-   */
-  public TextAreaPrintStream(final JTextArea textArea) {
-    super(new OutputStream() {
-      public void write(int b) {
-        textArea.append( String.valueOf((char)b) );
-        // Position ans Ende des Textes setzen
-        textArea.setCaretPosition( textArea.getText().lastIndexOf("\n")+1 );
-      }
-    } );
-  }
-}
+
+/**
+ * Diese Klasse stellt einen {@link PrintStream} dar, der an eine {@link JTextArea}
+ * gekoppelt ist. Jegliche Ausgabe, die auf den Stream geschrieben wird, wird
+ * in der TextArea ausgegeben
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class TextAreaPrintStream extends PrintStream {
+  /**
+   * Erzeugt einen neuen Stream.
+   * @param textArea Ausgabe-Komponente
+   */
+  public TextAreaPrintStream(final JTextArea textArea) {
+    super(new OutputStream() {
+      public void write(int b) {
+        textArea.append( String.valueOf((char)b) );
+        // Position ans Ende des Textes setzen
+        textArea.setCaretPosition( textArea.getText().lastIndexOf("\n")+1 );
+      }
+    } );
+  }
+}

Modified: trunk/src/schmitzm/swing/ToolTipComboBoxRenderer.java
===================================================================
--- trunk/src/schmitzm/swing/ToolTipComboBoxRenderer.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/ToolTipComboBoxRenderer.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,52 +1,70 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing;
-
-import java.awt.Component;
-import java.util.Map;
-
-import javax.swing.JList;
-import javax.swing.plaf.basic.BasicComboBoxRenderer;
-
-/**
- * Extends the {@link BasicComboBoxRenderer} with tooltip functionality.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- */
-public class ToolTipComboBoxRenderer extends BasicComboBoxRenderer {
-  /** Holds the tooltips for each list value */
-  protected Map<Object,String> tooltips = null;
-  
-  /**
-   * Creates a new renderer.
-   * @param tooltips map with tooltip for each list value (can be {@code null})
-   */
-  public ToolTipComboBoxRenderer(Map<Object,String> tooltips) {
-    super();
-    this.tooltips = tooltips;
-  }
-  
-  /**
-   * After calling the super method, the tooltip is set (if value is selected).
-   */
-  public Component getListCellRendererComponent(JList list, Object value,
-      int index, boolean isSelected, boolean cellHasFocus) {
-    // Create component
-    Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
-    // set tooltip, if item is selected
-    if ( tooltips != null && isSelected && index >= 0 ) {
-      String tooltip = tooltips.get(value);
-      list.setToolTipText(tooltip);
-    }
-    return c;
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
+
+import java.awt.Component;
+import java.util.Map;
+
+import javax.swing.JList;
+import javax.swing.plaf.basic.BasicComboBoxRenderer;
+
+/**
+ * Extends the {@link BasicComboBoxRenderer} with tooltip functionality.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ */
+public class ToolTipComboBoxRenderer extends BasicComboBoxRenderer {
+  /** Holds the tooltips for each list value */
+  protected Map<Object,String> tooltips = null;
+  
+  /**
+   * Creates a new renderer.
+   * @param tooltips map with tooltip for each list value (can be {@code null})
+   */
+  public ToolTipComboBoxRenderer(Map<Object,String> tooltips) {
+    super();
+    this.tooltips = tooltips;
+  }
+  
+  /**
+   * After calling the super method, the tooltip is set (if value is selected).
+   */
+  public Component getListCellRendererComponent(JList list, Object value,
+      int index, boolean isSelected, boolean cellHasFocus) {
+    // Create component
+    Component c = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+    // set tooltip, if item is selected
+    if ( tooltips != null && isSelected && index >= 0 ) {
+      String tooltip = tooltips.get(value);
+      list.setToolTipText(tooltip);
+    }
+    return c;
+  }
+
+}

Modified: trunk/src/schmitzm/swing/TreeSelectionDialog.java
===================================================================
--- trunk/src/schmitzm/swing/TreeSelectionDialog.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/TreeSelectionDialog.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,97 +1,115 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing;
-
-import java.awt.Component;
-import java.awt.Dimension;
-
-import javax.swing.JButton;
-import javax.swing.JDialog;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-import javax.swing.JTree;
-import javax.swing.event.TreeSelectionEvent;
-import javax.swing.event.TreeSelectionListener;
-import javax.swing.tree.DefaultMutableTreeNode;
-import javax.swing.tree.TreeModel;
-import javax.swing.tree.TreePath;
-import javax.swing.tree.TreeSelectionModel;
-
-/**
- * Diese Klasse stellt einen Dialog dar, der Objekte in einer Baumstruktur zur
- * Auswahl stellt.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class TreeSelectionDialog extends JOptionPane {
-  private TreeModel           model = null;
-  private JTree               tree  = null;
-  private TreeSelectionDialog THIS  = this;
-
-  /**
-   * Erzeugt einen neuen Dialog.
-   * @param model Daten-Basis fuer die darzustellenden Objekte
-   */
-  public TreeSelectionDialog(TreeModel model) {
-    super();
-    this.setPreferredSize(new Dimension(250,300));
-    this.validate();
-    this.model = model;
-    this.tree  = new JTree(model);
-    tree.setRootVisible(false);
-    this.setOptionType(JOptionPane.OK_CANCEL_OPTION);
-    this.setMessage( new JScrollPane(tree) );
-    // OK-Button soll nur aktiviert sein, wenn ein passendes Objekt
-    // ausgewaehlt ist
-    final JButton okButton = (JButton)((JPanel)THIS.getComponent(1)).getComponent(0);
-    okButton.setEnabled(false);
-    this.tree.addTreeSelectionListener( new TreeSelectionListener() {
-      public void valueChanged(TreeSelectionEvent e) {
-        okButton.setEnabled(
-            e.getNewLeadSelectionPath() != null &&
-            e.getNewLeadSelectionPath().getLastPathComponent() != null &&
-            e.getNewLeadSelectionPath().getLastPathComponent() instanceof DefaultMutableTreeNode &&
-            ((DefaultMutableTreeNode)e.getNewLeadSelectionPath().getLastPathComponent()).getUserObject() != null
-        );
-      }
-    });
-  }
-
-  /**
-   * Zeigt den Auswahldialog an.
-   * @param parent aufrufende Komponente
-   * @param title Titel fuer das Dialogfenster
-   * @param multipleSelect bestimmt, ob mehrere Baum-Elemente (Objekte) gleichzeitig
-   *        ausgewaehlt werden duerfen
-   * @return alle ausgewaehlten Objekte oder <code>null</code>, wenn der Dialog
-   *         abgebrochen wurde.
-   */
-  public Object[] show(Component parent, String title, boolean multipleSelect) {
-    if ( multipleSelect )
-      tree.getSelectionModel().setSelectionMode( TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION );
-    else
-      tree.getSelectionModel().setSelectionMode( TreeSelectionModel.SINGLE_TREE_SELECTION );
-
-    JDialog dialog = this.createDialog(parent,title);
-    dialog.setVisible(true);
-    // Dialog abgebrochen
-    if ( getValue() == null || ((Integer)getValue() != JOptionPane.OK_OPTION) )
-      return null;
-    // Dialog mit OK beendet
-    TreePath[] selPath = tree.getSelectionPaths();
-    Object[]   selObj = new Object[selPath.length];
-    for (int i=0; i<selObj.length; i++)
-      selObj[i] = ((DefaultMutableTreeNode)selPath[i].getLastPathComponent()).getUserObject();
-    return selObj;
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing;
+
+import java.awt.Component;
+import java.awt.Dimension;
+
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTree;
+import javax.swing.event.TreeSelectionEvent;
+import javax.swing.event.TreeSelectionListener;
+import javax.swing.tree.DefaultMutableTreeNode;
+import javax.swing.tree.TreeModel;
+import javax.swing.tree.TreePath;
+import javax.swing.tree.TreeSelectionModel;
+
+/**
+ * Diese Klasse stellt einen Dialog dar, der Objekte in einer Baumstruktur zur
+ * Auswahl stellt.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class TreeSelectionDialog extends JOptionPane {
+  private TreeModel           model = null;
+  private JTree               tree  = null;
+  private TreeSelectionDialog THIS  = this;
+
+  /**
+   * Erzeugt einen neuen Dialog.
+   * @param model Daten-Basis fuer die darzustellenden Objekte
+   */
+  public TreeSelectionDialog(TreeModel model) {
+    super();
+    this.setPreferredSize(new Dimension(250,300));
+    this.validate();
+    this.model = model;
+    this.tree  = new JTree(model);
+    tree.setRootVisible(false);
+    this.setOptionType(JOptionPane.OK_CANCEL_OPTION);
+    this.setMessage( new JScrollPane(tree) );
+    // OK-Button soll nur aktiviert sein, wenn ein passendes Objekt
+    // ausgewaehlt ist
+    final JButton okButton = (JButton)((JPanel)THIS.getComponent(1)).getComponent(0);
+    okButton.setEnabled(false);
+    this.tree.addTreeSelectionListener( new TreeSelectionListener() {
+      public void valueChanged(TreeSelectionEvent e) {
+        okButton.setEnabled(
+            e.getNewLeadSelectionPath() != null &&
+            e.getNewLeadSelectionPath().getLastPathComponent() != null &&
+            e.getNewLeadSelectionPath().getLastPathComponent() instanceof DefaultMutableTreeNode &&
+            ((DefaultMutableTreeNode)e.getNewLeadSelectionPath().getLastPathComponent()).getUserObject() != null
+        );
+      }
+    });
+  }
+
+  /**
+   * Zeigt den Auswahldialog an.
+   * @param parent aufrufende Komponente
+   * @param title Titel fuer das Dialogfenster
+   * @param multipleSelect bestimmt, ob mehrere Baum-Elemente (Objekte) gleichzeitig
+   *        ausgewaehlt werden duerfen
+   * @return alle ausgewaehlten Objekte oder <code>null</code>, wenn der Dialog
+   *         abgebrochen wurde.
+   */
+  public Object[] show(Component parent, String title, boolean multipleSelect) {
+    if ( multipleSelect )
+      tree.getSelectionModel().setSelectionMode( TreeSelectionModel.DISCONTIGUOUS_TREE_SELECTION );
+    else
+      tree.getSelectionModel().setSelectionMode( TreeSelectionModel.SINGLE_TREE_SELECTION );
+
+    JDialog dialog = this.createDialog(parent,title);
+    dialog.setVisible(true);
+    // Dialog abgebrochen
+    if ( getValue() == null || ((Integer)getValue() != JOptionPane.OK_OPTION) )
+      return null;
+    // Dialog mit OK beendet
+    TreePath[] selPath = tree.getSelectionPaths();
+    Object[]   selObj = new Object[selPath.length];
+    for (int i=0; i<selObj.length; i++)
+      selObj[i] = ((DefaultMutableTreeNode)selPath[i].getLastPathComponent()).getUserObject();
+    return selObj;
+  }
+}

Modified: trunk/src/schmitzm/swing/event/InputOptionAdapter.java
===================================================================
--- trunk/src/schmitzm/swing/event/InputOptionAdapter.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/event/InputOptionAdapter.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,45 +1,63 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing.event;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+import schmitzm.swing.InputOption;
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+/**
+ * Diese Klasse bildet eine Implementierung von {@link InputOptionListener},
+ * die nichts macht.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public abstract class InputOptionAdapter implements InputOptionListener {
+  /**
+   * Wird aufgerufen, wenn sich der Eingabewert des Option geaendert hat.
+   * @param inputOption Option, die sich geaendert hat
+   * @param oldValue alter Wert
+   * @param newValue neuer Wert
+   */
+  public void optionChanged(InputOption inputOption, Object oldValue, Object newValue) {
+  }
 
-package schmitzm.swing.event;
+  /**
+   * Wird aufgerufen, wenn die Eingabe-Komponente der Option den Fokus erhaelt.
+   * @param inputOption Option, die den Focus erhalten hat
+   */
+  public void optionGainedFocus(InputOption inputOption) {
+  }
 
-import schmitzm.swing.InputOption;
-
-/**
- * Diese Klasse bildet eine Implementierung von {@link InputOptionListener},
- * die nichts macht.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public abstract class InputOptionAdapter implements InputOptionListener {
-  /**
-   * Wird aufgerufen, wenn sich der Eingabewert des Option geaendert hat.
-   * @param inputOption Option, die sich geaendert hat
-   * @param oldValue alter Wert
-   * @param newValue neuer Wert
-   */
-  public void optionChanged(InputOption inputOption, Object oldValue, Object newValue) {
-  }
-
-  /**
-   * Wird aufgerufen, wenn die Eingabe-Komponente der Option den Fokus erhaelt.
-   * @param inputOption Option, die den Focus erhalten hat
-   */
-  public void optionGainedFocus(InputOption inputOption) {
-  }
-
-  /**
-   * Wird aufgerufen, wenn die Eingabe-Komponente der Option den Fokus verliert.
+  /**
+   * Wird aufgerufen, wenn die Eingabe-Komponente der Option den Fokus verliert.
    * @param inputOption Option, die den Focus verloren hat
-   */
-  public void optionLostFocus(InputOption inputOption) {
-  }
-}
+   */
+  public void optionLostFocus(InputOption inputOption) {
+  }
+}

Modified: trunk/src/schmitzm/swing/event/InputOptionListener.java
===================================================================
--- trunk/src/schmitzm/swing/event/InputOptionListener.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/event/InputOptionListener.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,43 +1,61 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing.event;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+import schmitzm.swing.InputOption;
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+/**
+ * Dieser Listener verfolgt die Eingaben in einer {@link schmitzm.swing.InputOption}.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public interface InputOptionListener {
+  /**
+   * Wird aufgerufen, wenn sich der Eingabewert des Option geaendert hat.
+   * @param inputOption Option, die sich geaendert hat
+   * @param oldValue alter Wert
+   * @param newValue neuer Wert
+   */
+  public void optionChanged(InputOption inputOption, Object oldValue, Object newValue);
 
-package schmitzm.swing.event;
+  /**
+   * Wird aufgerufen, wenn die Eingabe-Komponente der Option den Fokus
+   * erhaelt.
+   * @param inputOption Option, die den Focus erhalten hat
+   */
+  public void optionGainedFocus(InputOption inputOption);
 
-import schmitzm.swing.InputOption;
-
-/**
- * Dieser Listener verfolgt die Eingaben in einer {@link schmitzm.swing.InputOption}.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public interface InputOptionListener {
-  /**
-   * Wird aufgerufen, wenn sich der Eingabewert des Option geaendert hat.
-   * @param inputOption Option, die sich geaendert hat
-   * @param oldValue alter Wert
-   * @param newValue neuer Wert
-   */
-  public void optionChanged(InputOption inputOption, Object oldValue, Object newValue);
-
-  /**
-   * Wird aufgerufen, wenn die Eingabe-Komponente der Option den Fokus
-   * erhaelt.
-   * @param inputOption Option, die den Focus erhalten hat
-   */
-  public void optionGainedFocus(InputOption inputOption);
-
-  /**
-   * Wird aufgerufen, wenn die Eingabe-Komponente der Option den Fokus
-   * verliert.
+  /**
+   * Wird aufgerufen, wenn die Eingabe-Komponente der Option den Fokus
+   * verliert.
    * @param inputOption Option, die den Focus verloren hat
-   */
-  public void optionLostFocus(InputOption inputOption);
-}
+   */
+  public void optionLostFocus(InputOption inputOption);
+}

Modified: trunk/src/schmitzm/swing/event/MouseAdapter.java
===================================================================
--- trunk/src/schmitzm/swing/event/MouseAdapter.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/event/MouseAdapter.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,30 +1,59 @@
-package schmitzm.swing.event;
-
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseMotionListener;
-
-/**
- * Diese Klasse erweitert den {@link java.awt.event.MouseAdapter} um die
- * Funktionen des {@link MouseMotionListener}.<br>
- * <b>Diese Klasse stellt einen Workaround fuer Java 1.5 dar. In Java 1.6 ist
- * diese Funktionalitaet bereits im {@link java.awt.event.MouseAdapter}
- * enthalten!</b>
- * @deprecated
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class MouseAdapter extends java.awt.event.MouseAdapter implements MouseMotionListener {
-  /**
-   * Macht nichts.
-   * @param e Maus-Ereignis
-   */
-  public void mouseDragged(MouseEvent e) {
-  }
-
-  /**
-   * Macht nichts.
-   * @param e Maus-Ereignis
-   */
-  public void mouseMoved(MouseEvent e) {
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing.event;
+
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseMotionListener;
+
+/**
+ * Diese Klasse erweitert den {@link java.awt.event.MouseAdapter} um die
+ * Funktionen des {@link MouseMotionListener}.<br>
+ * <b>Diese Klasse stellt einen Workaround fuer Java 1.5 dar. In Java 1.6 ist
+ * diese Funktionalitaet bereits im {@link java.awt.event.MouseAdapter}
+ * enthalten!</b>
+ * @deprecated
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class MouseAdapter extends java.awt.event.MouseAdapter implements MouseMotionListener {
+  /**
+   * Macht nichts.
+   * @param e Maus-Ereignis
+   */
+  public void mouseDragged(MouseEvent e) {
+  }
+
+  /**
+   * Macht nichts.
+   * @param e Maus-Ereignis
+   */
+  public void mouseMoved(MouseEvent e) {
+  }
+}

Modified: trunk/src/schmitzm/swing/event/PopupMenuListener.java
===================================================================
--- trunk/src/schmitzm/swing/event/PopupMenuListener.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/event/PopupMenuListener.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,67 +1,85 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing.event;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing.event;
-
 import java.awt.Component;
 import java.awt.event.MouseEvent;
 
 import javax.swing.JPopupMenu;
 import javax.swing.event.MouseInputAdapter;
-
-/**
- * Diese Klasse implementiert einen MouseListener, der auf einen
- * PopupTrigger lauscht. Sofern dieser erfolgt, wird ein Popup-Menue
- * angezeigt.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class PopupMenuListener extends MouseInputAdapter {
-  private JPopupMenu menu;
-
-  /**
-   * Erzeugt einen neuen Listener
-   * @param menu Popup-Menue, welches geoeffnet werden soll
-   */
-  public PopupMenuListener(JPopupMenu menu) {
-    super();
-    this.menu = menu;
-  }
-
-  /**
-   * Checkt, ob ein PopupTrigger (i.A. Rechtsklick) auf eine mit dem
-   * PopupMenue verbundene Komponente stattgefunden hat.
-   * Ist dies der Fall, wird das PopupMenue geoeffnet.
-   */
-  protected void checkPopupSignal(MouseEvent e) {
-    if ( e.isPopupTrigger() ) {
-      menu.show( (Component)e.getSource(), e.getX(), e.getY() );
-      e.consume();
-    }
-  }
-
-  /**
-   * Prueft auf <code>MouseEvent.isPopupTrigger()</code> und zeigt gegebenfalls
-   * das Menu an.
-   */
-  public void mousePressed(MouseEvent e) {
-    checkPopupSignal(e);
-
-  }
-
-  /**
-   * Prueft auf <code>MouseEvent.isPopupTrigger()</code> und zeigt gegebenfalls
-   * das Menu an.
-   */
-  public void mouseReleased(MouseEvent e) {
-    checkPopupSignal(e);
-  }
-}
+
+/**
+ * Diese Klasse implementiert einen MouseListener, der auf einen
+ * PopupTrigger lauscht. Sofern dieser erfolgt, wird ein Popup-Menue
+ * angezeigt.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class PopupMenuListener extends MouseInputAdapter {
+  private JPopupMenu menu;
+
+  /**
+   * Erzeugt einen neuen Listener
+   * @param menu Popup-Menue, welches geoeffnet werden soll
+   */
+  public PopupMenuListener(JPopupMenu menu) {
+    super();
+    this.menu = menu;
+  }
+
+  /**
+   * Checkt, ob ein PopupTrigger (i.A. Rechtsklick) auf eine mit dem
+   * PopupMenue verbundene Komponente stattgefunden hat.
+   * Ist dies der Fall, wird das PopupMenue geoeffnet.
+   */
+  protected void checkPopupSignal(MouseEvent e) {
+    if ( e.isPopupTrigger() ) {
+      menu.show( (Component)e.getSource(), e.getX(), e.getY() );
+      e.consume();
+    }
+  }
+
+  /**
+   * Prueft auf <code>MouseEvent.isPopupTrigger()</code> und zeigt gegebenfalls
+   * das Menu an.
+   */
+  public void mousePressed(MouseEvent e) {
+    checkPopupSignal(e);
+
+  }
+
+  /**
+   * Prueft auf <code>MouseEvent.isPopupTrigger()</code> und zeigt gegebenfalls
+   * das Menu an.
+   */
+  public void mouseReleased(MouseEvent e) {
+    checkPopupSignal(e);
+  }
+}

Modified: trunk/src/schmitzm/swing/event/PropertyChangeEmitter.java
===================================================================
--- trunk/src/schmitzm/swing/event/PropertyChangeEmitter.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/event/PropertyChangeEmitter.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,69 +1,88 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.swing.event;
-
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.util.Vector;
-
-/**
- * This class provides a super class for all classes which initiates
- * {@link PropertyChangeEvent PropertyChangeEvents} to
- * {@link PropertyChangeListener PropertyChangeListeners}. 
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- */
-public abstract class PropertyChangeEmitter<E extends PropertyChangeListener> {
-  /** Holds the connected listeners. */
-  protected Vector<E> listenerList = new Vector<E>();
-  /** Flag to (temporary) disable firing events. Useful if several changes
-   *  should be performed and fired collectively. */
-  protected boolean eventFiringEnabled = true;
-
-  /**
-   * Adds a listener to the listener list.
-   * @param listener a listener
-   */
-  public void addListener(E listener) {
-    listenerList.add(listener);
-  }
-  
-  /**
-   * Removes a listener from the listener list.
-   * @param listener a listener
-   */
-  public void removeListener(E listener) {
-    listenerList.remove(listener);
-  }
-  
-  /**
-   * Fires the {@link PropertyChangeEvent} to all connected
-   * {@link PropertyChangeListener PropertyChangeListeners} except
-   * the specified ones. Does nothing if {@link #eventFiringEnabled} is
-   * set to {@code false}.
-   * @param e an event
-   * @param exceptListeners listeners which are not notified (useful to avoid
-   *                        event circles)
-   */
-  protected void firePropertyChangeEvent(PropertyChangeEvent e, PropertyChangeListener... exceptListeners) {
-    if ( !eventFiringEnabled )
-      return;
-
-    Vector<PropertyChangeListener> exceptList = new Vector<PropertyChangeListener>();
-    for (PropertyChangeListener l : exceptListeners)
-      exceptList.add(l);
-    
-    for (PropertyChangeListener listener : listenerList){
-      if ( !exceptList.contains(listener))
-        listener.propertyChange(e);
-    }
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing.event;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.Vector;
+
+/**
+ * This class provides a super class for all classes which initiates
+ * {@link PropertyChangeEvent PropertyChangeEvents} to
+ * {@link PropertyChangeListener PropertyChangeListeners}. 
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ */
+public abstract class PropertyChangeEmitter<E extends PropertyChangeListener> {
+  /** Holds the connected listeners. */
+  protected Vector<E> listenerList = new Vector<E>();
+  /** Flag to (temporary) disable firing events. Useful if several changes
+   *  should be performed and fired collectively. */
+  protected boolean eventFiringEnabled = true;
+
+  /**
+   * Adds a listener to the listener list.
+   * @param listener a listener
+   */
+  public void addListener(E listener) {
+    listenerList.add(listener);
+  }
+  
+  /**
+   * Removes a listener from the listener list.
+   * @param listener a listener
+   */
+  public void removeListener(E listener) {
+    listenerList.remove(listener);
+  }
+  
+  /**
+   * Fires the {@link PropertyChangeEvent} to all connected
+   * {@link PropertyChangeListener PropertyChangeListeners} except
+   * the specified ones. Does nothing if {@link #eventFiringEnabled} is
+   * set to {@code false}.
+   * @param e an event
+   * @param exceptListeners listeners which are not notified (useful to avoid
+   *                        event circles)
+   */
+  protected void firePropertyChangeEvent(PropertyChangeEvent e, PropertyChangeListener... exceptListeners) {
+    if ( !eventFiringEnabled )
+      return;
+
+    Vector<PropertyChangeListener> exceptList = new Vector<PropertyChangeListener>();
+    for (PropertyChangeListener l : exceptListeners)
+      exceptList.add(l);
+    
+    for (PropertyChangeListener listener : listenerList){
+      if ( !exceptList.contains(listener))
+        listener.propertyChange(e);
+    }
+  }
+
+}

Modified: trunk/src/schmitzm/swing/event/WindowEventConnector.java
===================================================================
--- trunk/src/schmitzm/swing/event/WindowEventConnector.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/event/WindowEventConnector.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,112 +1,130 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing.event;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing.event;
-
 import java.awt.Dialog;
 import java.awt.Frame;
 import java.awt.Window;
 import java.awt.event.WindowAdapter;
 import java.awt.event.WindowEvent;
-
-/**
- * Dieser {@link WindowAdapter} verbindet ein (Unter-)Fenster mit den Aktionen
- * eines anderen (Haupt-)Fensters.<br>
- * Wird das Haupt-Fenster geschlossen oder minimiert, wird auch das verbundene
- * Unter-Fenster verborgen. Wird das Haupt-Fenster geoeffnet, wird auch das
- * Unter-Fenster angezeigt, sofern es beim Schliessen des Haupt-Fensters
- * geoeffnet war.<br>
- * Fuer jedes Unter-Fenster wird ein <code>WindowEventConnector</code> erzeugt
- * und als {@link Window#addWindowListener WindowListener} an das Haupt-Fenster
- * gekoppelt.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class WindowEventConnector extends WindowAdapter {
-  /** Kontrolliertes Unter-Fenster. */
-  protected Window    window     = null;
-  /** Speichert den Status des Unter-Fensters, wenn das Haupt-Fenster geschlossen
-   *  oder minimiert wird.*/
-  protected boolean   wasVisible = false;
-
-  /**
-   * Erzeugt einen neuen Connector.
-   * @param window durch den Connector gesteuertes (Unter-)Fenster
-   */
-  public WindowEventConnector(Window window) {
-    super();
-    this.window = window;
-  }
-
-  /**
-   * Wird aufgerufen, wenn das Haupt-Fenster geschlossen wird. Bevor das Unter-Fenster
-   * ebenfalls geschlossen wird, wird sein Status gesichtert.
-   * @see #wasVisible
-   */
-  public void windowClosed(WindowEvent e) {
-    wasVisible = window.isVisible();
-    window.setVisible(false);
-  }
-
-  /**
-   * Wird aufgerufen, wenn das Haupt-Fenster ueber das System-Menue geschlossen
-   * wird. Bevor das Unter-Fenster ebenfalls geschlossen wird, wird sein Status
-   * gesichert.
-   * @see #wasVisible
-   */
-  public void windowClosing(WindowEvent e) {
-    windowClosed(e);
-  }
-
-  /**
-   * Wird aufgerufen, wenn das Haupt-Fenster geoeffnet wird. War das Unter-Fenster
-   * zuvor geoeffnet, wird es ebenfalls wieder angezeigt.
-   */
-  public void windowOpened(WindowEvent e) {
-    if ( !window.isVisible() )
-      window.setVisible(wasVisible);
-  }
-
-// KLAPPT NICHT WIE GEWUENSCHT
-//  /**
-//   * Wird aufgerufen, wenn das Haupt-Fenster aktiviert wird.
-//   */
-//  public void windowActivated(WindowEvent e) {
-//    windowOpened(e);
-//  }
-
-  /**
-   * Wird aufgerufen, wenn das Haupt-Fenster minimiert wird. Handelt es sich
-   * bei dem Unter-Fenster um einen {@link Frame}, wird auch dieses minimiert.
-   * Andernfalls (z.B. bei einem {@link Dialog}) wird das Unter-Fenster
-   * verborgen.
-   */
-  public void windowIconified(WindowEvent e) {
-    if ( window instanceof Frame )
-      ((Frame)window).setState(Frame.ICONIFIED);
-    else
-      windowClosed(e);
-  }
-
-  /**
-   * Wird aufgerufen, wenn das Haupt-Fenster "deminimiert" wird. Handelt es sich
-   * bei dem Unter-Fenster um einen {@link Frame}, wird auch dieses "deminimiert".
-   * Andernfalls (z.B. bei einem {@link Dialog}) wird das Unter-Fenster
-   * wieder angezeigt.
-   */
-  public void windowDeiconified(WindowEvent e) {
-    if ( window instanceof Frame )
-      ((Frame)window).setState(Frame.NORMAL);
-    else
-      windowOpened(e);
-  }
-
-}
+
+/**
+ * Dieser {@link WindowAdapter} verbindet ein (Unter-)Fenster mit den Aktionen
+ * eines anderen (Haupt-)Fensters.<br>
+ * Wird das Haupt-Fenster geschlossen oder minimiert, wird auch das verbundene
+ * Unter-Fenster verborgen. Wird das Haupt-Fenster geoeffnet, wird auch das
+ * Unter-Fenster angezeigt, sofern es beim Schliessen des Haupt-Fensters
+ * geoeffnet war.<br>
+ * Fuer jedes Unter-Fenster wird ein <code>WindowEventConnector</code> erzeugt
+ * und als {@link Window#addWindowListener WindowListener} an das Haupt-Fenster
+ * gekoppelt.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class WindowEventConnector extends WindowAdapter {
+  /** Kontrolliertes Unter-Fenster. */
+  protected Window    window     = null;
+  /** Speichert den Status des Unter-Fensters, wenn das Haupt-Fenster geschlossen
+   *  oder minimiert wird.*/
+  protected boolean   wasVisible = false;
+
+  /**
+   * Erzeugt einen neuen Connector.
+   * @param window durch den Connector gesteuertes (Unter-)Fenster
+   */
+  public WindowEventConnector(Window window) {
+    super();
+    this.window = window;
+  }
+
+  /**
+   * Wird aufgerufen, wenn das Haupt-Fenster geschlossen wird. Bevor das Unter-Fenster
+   * ebenfalls geschlossen wird, wird sein Status gesichtert.
+   * @see #wasVisible
+   */
+  public void windowClosed(WindowEvent e) {
+    wasVisible = window.isVisible();
+    window.setVisible(false);
+  }
+
+  /**
+   * Wird aufgerufen, wenn das Haupt-Fenster ueber das System-Menue geschlossen
+   * wird. Bevor das Unter-Fenster ebenfalls geschlossen wird, wird sein Status
+   * gesichert.
+   * @see #wasVisible
+   */
+  public void windowClosing(WindowEvent e) {
+    windowClosed(e);
+  }
+
+  /**
+   * Wird aufgerufen, wenn das Haupt-Fenster geoeffnet wird. War das Unter-Fenster
+   * zuvor geoeffnet, wird es ebenfalls wieder angezeigt.
+   */
+  public void windowOpened(WindowEvent e) {
+    if ( !window.isVisible() )
+      window.setVisible(wasVisible);
+  }
+
+// KLAPPT NICHT WIE GEWUENSCHT
+//  /**
+//   * Wird aufgerufen, wenn das Haupt-Fenster aktiviert wird.
+//   */
+//  public void windowActivated(WindowEvent e) {
+//    windowOpened(e);
+//  }
+
+  /**
+   * Wird aufgerufen, wenn das Haupt-Fenster minimiert wird. Handelt es sich
+   * bei dem Unter-Fenster um einen {@link Frame}, wird auch dieses minimiert.
+   * Andernfalls (z.B. bei einem {@link Dialog}) wird das Unter-Fenster
+   * verborgen.
+   */
+  public void windowIconified(WindowEvent e) {
+    if ( window instanceof Frame )
+      ((Frame)window).setState(Frame.ICONIFIED);
+    else
+      windowClosed(e);
+  }
+
+  /**
+   * Wird aufgerufen, wenn das Haupt-Fenster "deminimiert" wird. Handelt es sich
+   * bei dem Unter-Fenster um einen {@link Frame}, wird auch dieses "deminimiert".
+   * Andernfalls (z.B. bei einem {@link Dialog}) wird das Unter-Fenster
+   * wieder angezeigt.
+   */
+  public void windowDeiconified(WindowEvent e) {
+    if ( window instanceof Frame )
+      ((Frame)window).setState(Frame.NORMAL);
+    else
+      windowOpened(e);
+  }
+
+}

Modified: trunk/src/schmitzm/swing/log4j/LoggerConfigurationTableModel.java
===================================================================
--- trunk/src/schmitzm/swing/log4j/LoggerConfigurationTableModel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/log4j/LoggerConfigurationTableModel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,16 +1,34 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing.log4j;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing.log4j;
-
 import java.util.Comparator;
 import java.util.Enumeration;
 import java.util.TreeSet;
@@ -23,141 +41,141 @@
 import org.apache.log4j.Level;
 import org.apache.log4j.LogManager;
 import org.apache.log4j.Logger;
-
-/**
- * Diese Klasse stellt ein {@link TableModel} dar, in dem die aktuell
- * im {@link LogManager} registrierten Log4j-Logger in 4 Spalten angezeigt werden.
- * <ol start=0>
- *   <li>{@linkplain Logger#getName() Logger-Name} (Typ {@link String})</li>
- *   <li>{@linkplain Logger#getLevel() Logger-Level} (Typ {@link Level})</li>
- *   <li>{@linkplain Logger#getAdditivity() Logger-Additiviaet (Rekursive Verarbeitung der Vater-Appender)} (Typ {@link Boolean})</li>
- *   <li>Appender-Liste (Typ {@link Appender Enumeration&lt;Appender&gt;})</li>
- * </ol>
- * <b><u>Beachte</u>:</b><br>
- * Nur die Spalten 1 (Level) und 2 (Additivitaet) sind als veraenderbar vorgesehen!
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class LoggerConfigurationTableModel extends AbstractTableModel {
-  /** Spalten-Namen der Tabelle. */
-  public final String[] COL_NAME = new String[] {"Logger","Level","Additivity","Appender list"};
-  /** Spalten-Typen der Tabelle.
-   *  <ol start=0>
-   *    <li>{@link String}</li>
-   *    <li>{@link Level}</li>
-   *    <li>{@link Boolean}</li>
-   *    <li>{@link Enumeration}</li>
-   *  </ol> */
-  public final Class[] COL_TYPE = new Class[] {String.class,Level.class,Boolean.class,Enumeration.class};
-
-  /** {@link LogManager#getCurrentLoggers()} liefert eine {@link Enumeration}.
-   *  Fuer einen wahlfreien Zugriff, werden die Logger bei der {@link #refresh()}-Aktion
-   *  in ein {@link Vector} kopiert. */
-  protected Vector<Logger> loggers = new Vector<Logger>();
-
-  /**
-   * Erzeugt ein neues Tabellenmodell.
-   */
-  public LoggerConfigurationTableModel() {
-    super();
-    refresh();
-  }
-
-  /**
-   * Aktualisiert die Tabelle auf Basis der aktuelle registrierten
-   * Logger.
-   * @see LogManager#getCurrentLoggers()
-   */
-  public void refresh() {
-    loggers.clear();
-    loggers.add( LogManager.getRootLogger() );
-    Enumeration<Logger> newLoggers = LogManager.getCurrentLoggers();
-    // Fuer die Sortierung die Logger in ein TreeSet einfuegen
-    TreeSet<Logger> sortedLoggers = new TreeSet<Logger>( new Comparator<Logger>() {
-      public int compare(Logger logger1, Logger logger2) {
-        return logger1.getName().compareTo( logger2.getName() );
-      }
-    });
-    for (; newLoggers != null && newLoggers.hasMoreElements(); )
-      sortedLoggers.add( newLoggers.nextElement() );
-
-    // Die sortierten Logger der Reihe nach in die Logger-Liste einfuegen
-    for (; !sortedLoggers.isEmpty();) {
-      loggers.add(sortedLoggers.first());
-      sortedLoggers.remove( sortedLoggers.first() );
-    }
-    this.fireTableDataChanged();
-  }
-
-  /**
-   * Liefert die Anzahl an Zeilen (Loggern) der Tabelle.
-   */
-  public int getRowCount() {
-    return loggers.size();
-  }
-
-  /**
-   * Liefert die Spaltenanzahl der Tabelle. Immer 3.
-   */
-  public int getColumnCount() {
-    return COL_NAME.length;
-  }
-
-  /**
-   * Liefert einen Spaltennamen der Tabelle.
-   */
-  public String getColumnName(int col) {
-    return COL_NAME[col];
-  }
-
-  /**
-   * Liefert den Typ einer Tabellen-Spalte.
-   */
-  public Class getColumnClass(int col) {
-    return COL_TYPE[col];
-  }
-
-  /**
-   * Liefert einen Zellenwert der Tabelle.
-   * @param row Zeilenindex (beginnend bei 0)
-   * @param col Spaltenindex (beginnend bei 0)
-   */
-  public Object getValueAt(int row, int col) {
-    Logger logger = loggers.elementAt(row);
-    switch (col) {
-      case 0: return logger.getName();
-      case 1: return logger.getLevel();
-      case 2: return logger.getAdditivity();
-      case 3: return logger.getAllAppenders();
-    }
-    return null;
-  }
-
-  /**
-   * Prueft, ob eine Zeile editierbar ist.
-   * @param row Zeilenindex (beginnend bei 0)
-   * @param col Spaltenindex (beginnend bei 0)
-   * @return {@code true} nur fuer Spalte 1 (Logger-Level) und Spalte 3
-   * (Additivitaet)
-   */
-  public boolean isCellEditable(int row, int col) {
-    return col == 1 || col == 2;
-  }
-
-  /**
-   * Setzt einen Zellenwert der Tabelle. Nur relevant fuer die Spalten 1 (Level)
-   * und 2 (Additivitaet).
-   * @param value neue Wert
-   * @param row Zeilenindex (beginnend bei 0)
-   * @param col Spaltenindex (beginnend bei 0)
-   */
-  public void setValueAt(Object value, int row, int col) {
-    Logger logger = loggers.elementAt(row);
-    switch (col) {
-      case 1: logger.setLevel( (Level)value );
-              break;
-      case 2: logger.setAdditivity( (Boolean)value );
-              break;
-    }
-  }
-}
+
+/**
+ * Diese Klasse stellt ein {@link TableModel} dar, in dem die aktuell
+ * im {@link LogManager} registrierten Log4j-Logger in 4 Spalten angezeigt werden.
+ * <ol start=0>
+ *   <li>{@linkplain Logger#getName() Logger-Name} (Typ {@link String})</li>
+ *   <li>{@linkplain Logger#getLevel() Logger-Level} (Typ {@link Level})</li>
+ *   <li>{@linkplain Logger#getAdditivity() Logger-Additiviaet (Rekursive Verarbeitung der Vater-Appender)} (Typ {@link Boolean})</li>
+ *   <li>Appender-Liste (Typ {@link Appender Enumeration&lt;Appender&gt;})</li>
+ * </ol>
+ * <b><u>Beachte</u>:</b><br>
+ * Nur die Spalten 1 (Level) und 2 (Additivitaet) sind als veraenderbar vorgesehen!
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class LoggerConfigurationTableModel extends AbstractTableModel {
+  /** Spalten-Namen der Tabelle. */
+  public final String[] COL_NAME = new String[] {"Logger","Level","Additivity","Appender list"};
+  /** Spalten-Typen der Tabelle.
+   *  <ol start=0>
+   *    <li>{@link String}</li>
+   *    <li>{@link Level}</li>
+   *    <li>{@link Boolean}</li>
+   *    <li>{@link Enumeration}</li>
+   *  </ol> */
+  public final Class[] COL_TYPE = new Class[] {String.class,Level.class,Boolean.class,Enumeration.class};
+
+  /** {@link LogManager#getCurrentLoggers()} liefert eine {@link Enumeration}.
+   *  Fuer einen wahlfreien Zugriff, werden die Logger bei der {@link #refresh()}-Aktion
+   *  in ein {@link Vector} kopiert. */
+  protected Vector<Logger> loggers = new Vector<Logger>();
+
+  /**
+   * Erzeugt ein neues Tabellenmodell.
+   */
+  public LoggerConfigurationTableModel() {
+    super();
+    refresh();
+  }
+
+  /**
+   * Aktualisiert die Tabelle auf Basis der aktuelle registrierten
+   * Logger.
+   * @see LogManager#getCurrentLoggers()
+   */
+  public void refresh() {
+    loggers.clear();
+    loggers.add( LogManager.getRootLogger() );
+    Enumeration<Logger> newLoggers = LogManager.getCurrentLoggers();
+    // Fuer die Sortierung die Logger in ein TreeSet einfuegen
+    TreeSet<Logger> sortedLoggers = new TreeSet<Logger>( new Comparator<Logger>() {
+      public int compare(Logger logger1, Logger logger2) {
+        return logger1.getName().compareTo( logger2.getName() );
+      }
+    });
+    for (; newLoggers != null && newLoggers.hasMoreElements(); )
+      sortedLoggers.add( newLoggers.nextElement() );
+
+    // Die sortierten Logger der Reihe nach in die Logger-Liste einfuegen
+    for (; !sortedLoggers.isEmpty();) {
+      loggers.add(sortedLoggers.first());
+      sortedLoggers.remove( sortedLoggers.first() );
+    }
+    this.fireTableDataChanged();
+  }
+
+  /**
+   * Liefert die Anzahl an Zeilen (Loggern) der Tabelle.
+   */
+  public int getRowCount() {
+    return loggers.size();
+  }
+
+  /**
+   * Liefert die Spaltenanzahl der Tabelle. Immer 3.
+   */
+  public int getColumnCount() {
+    return COL_NAME.length;
+  }
+
+  /**
+   * Liefert einen Spaltennamen der Tabelle.
+   */
+  public String getColumnName(int col) {
+    return COL_NAME[col];
+  }
+
+  /**
+   * Liefert den Typ einer Tabellen-Spalte.
+   */
+  public Class getColumnClass(int col) {
+    return COL_TYPE[col];
+  }
+
+  /**
+   * Liefert einen Zellenwert der Tabelle.
+   * @param row Zeilenindex (beginnend bei 0)
+   * @param col Spaltenindex (beginnend bei 0)
+   */
+  public Object getValueAt(int row, int col) {
+    Logger logger = loggers.elementAt(row);
+    switch (col) {
+      case 0: return logger.getName();
+      case 1: return logger.getLevel();
+      case 2: return logger.getAdditivity();
+      case 3: return logger.getAllAppenders();
+    }
+    return null;
+  }
+
+  /**
+   * Prueft, ob eine Zeile editierbar ist.
+   * @param row Zeilenindex (beginnend bei 0)
+   * @param col Spaltenindex (beginnend bei 0)
+   * @return {@code true} nur fuer Spalte 1 (Logger-Level) und Spalte 3
+   * (Additivitaet)
+   */
+  public boolean isCellEditable(int row, int col) {
+    return col == 1 || col == 2;
+  }
+
+  /**
+   * Setzt einen Zellenwert der Tabelle. Nur relevant fuer die Spalten 1 (Level)
+   * und 2 (Additivitaet).
+   * @param value neue Wert
+   * @param row Zeilenindex (beginnend bei 0)
+   * @param col Spaltenindex (beginnend bei 0)
+   */
+  public void setValueAt(Object value, int row, int col) {
+    Logger logger = loggers.elementAt(row);
+    switch (col) {
+      case 1: logger.setLevel( (Level)value );
+              break;
+      case 2: logger.setAdditivity( (Boolean)value );
+              break;
+    }
+  }
+}

Modified: trunk/src/schmitzm/swing/log4j/LoggerFrame.java
===================================================================
--- trunk/src/schmitzm/swing/log4j/LoggerFrame.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/log4j/LoggerFrame.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,249 +1,267 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing.log4j;
-
-import java.awt.Component;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.io.File;
-import java.util.Enumeration;
-
-import javax.swing.DefaultCellEditor;
-import javax.swing.JButton;
-import javax.swing.JCheckBox;
-import javax.swing.JComboBox;
-import javax.swing.JFrame;
-import javax.swing.JScrollPane;
-import javax.swing.JTable;
-
-import org.apache.log4j.Appender;
-import org.apache.log4j.ConsoleAppender;
-import org.apache.log4j.FileAppender;
-import org.apache.log4j.Level;
-import org.apache.log4j.LogManager;
-import org.apache.log4j.Logger;
-import org.apache.log4j.PropertyConfigurator;
-import org.apache.log4j.spi.LoggerRepository;
-
-import schmitzm.swing.ExceptionDialog;
-import schmitzm.swing.FileInputOption;
-import schmitzm.swing.SwingUtil;
-import schmitzm.swing.table.ComponentRenderer;
-
-/**
- * Diese Klasse stellt ein Fenster dar, in dem die aktuell im {@link LogManager}
- * registrierten Log4j-Logger als Tabelle dargestellt sind.
- * <ol>
- *   <li>Logger-Name</li>
- *   <li>Level</li>
- *   <li>Additivitaet (ob rekursiv auch die Vater-Appender ausgefuehrt werden)</li>
- *   <li>Dateinamen der {@link FileAppender}, "CONSOLE" fuer {@link ConsoleAppender}</li>
- * </ol>
- * Ueber einen {@linkplain #refresh() Refresh-Button} kann die Tabelle jederzeit aktualisiert
- * werden. Es koennen <b>keine</b> Logger hinzugefuegt oder entfernt werden.
- * Veraendert werden koennen die Logger nur hinsichtlich ihres Levels und ihrer
- * Addititvitaet.<br>
- * Die Eingabe-Maske bietet jedoch die Moeglichkeit, eine Logger-Konfiguration
- * aus einer {@linkplain PropertyConfigurator#doConfigure(String,LoggerRepository) Log4j-Konfigurationsdatei}
- * (neu) zu laden.<br>
- * <b><u>Beachte</u>:</b><br>
- * Beim Neu-Laden werden lediglich die <u>explizit</u> in der Datei spezifizierten
- * Logger-Konfigurationen aktualisiert. Vom der Applikation erzeugte Logger bleiben
- * erhalten (und koennen auch nicht mehr geloescht werden)!
- * Ebenso bleiben alle Logger-Properties unveraendert erhalten, die nicht
- * <u>explizit</u> in der Konfigurationsdatei angegeben sind. Wird z.B. die
- * Additivitaet eines Loggers in der Datei nicht gesetzt, wird sie beim ersten
- * Einlesen per Default auf {@code true} gesetzt. Wird sie durch den Anwender
- * abgeaendert, bleibt diese Einstellung erhalten, auch wenn die Datei neu
- * eingelesen wird.
- * @see LoggerConfigurationTableModel
- * @see Logger
- * @see LogManager
- * @see PropertyConfigurator#configure(String)
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class LoggerFrame extends JFrame {
-  /** Eingabe-Feld fuer die Log4j-Konfigurationsdatei. */
-  protected FileInputOption configFileField =  new FileInputOption(null,false);
-  /** Butten, ueber den die Log4j-Konfigurationsdatei neu geladen wird.
-   *  @see #reload() */
-  protected JButton reloadButton = new JButton( SwingUtil.RESOURCE.getString("Reload") );
-  /** Butten, ueber den die Logger-Tabelle aktualisiert wird.
-   *  @see #refresh() */
-  protected JButton refreshButton = new JButton( SwingUtil.RESOURCE.getString("Refresh") );
-  /** Tabelle, in der die Logger angezeigt werden.
-   *  @see #loggerTableModel */
-  protected JTable loggerTable = null;
-  /** Datenbasis fuer die Logger-Tabelle. */
-  protected LoggerConfigurationTableModel loggerTableModel = null;
-
-  /**
-   * Erzeugt ein neues Fenster.
-   * @param file vorgeblendete Log4j-Konfigurationsdatei
-   */
-  public LoggerFrame(File file) {
-    super("Log4j Logger configuration");
-    initGUI();
-    configFileField.setValue(file);
-  }
-
-  /**
-   * Erzeugt ein neues Fenster.
-   */
-  public LoggerFrame() {
-    this(null);
-  }
-
-  /**
-   * Initialisiert das Fenster-Layout.
-   */
-  protected void initGUI() {
-    this.setLayout( new GridBagLayout() );
-    this.setSize(400,300);
-    // Logger-Tabelle
-    loggerTableModel = new LoggerConfigurationTableModel();
-    loggerTable = new JTable(loggerTableModel);
-    loggerTable.setCellSelectionEnabled(false);
-    loggerTable.setRowHeight( new JComboBox().getPreferredSize().height );
-    loggerTable.setDefaultRenderer( Enumeration.class, new ComponentRenderer() {
-      public Component createRendererComponent( JTable table,
-                                                Object value,
-                                                boolean isSelected,
-                                                boolean hasFocus,
-                                                int row,
-                                                int column) {
-
-        // Appender in String umwandeln
-        if ( value instanceof Enumeration )
-          value = getStringFromAppenders((Enumeration<Appender>)value);
-        return super.createRendererComponent(table,value,isSelected,hasFocus,row,column);
-      }
-    });
-    loggerTable.setDefaultRenderer( Boolean.class, new ComponentRenderer.JCheckBox());
-    loggerTable.setDefaultEditor( Boolean.class, new DefaultCellEditor( new JCheckBox() {
-      public int getHorizontalAlignment() {
-        return this.CENTER;
-      }
-      public int getVerticalAlignment() {
-        return this.CENTER;
-      }
-    }));
-
-    loggerTable.setDefaultRenderer( Level.class, new ComponentRenderer.JComboBox() );
-    loggerTable.setDefaultEditor( Level.class, new DefaultCellEditor( new JComboBox( new Object[] {
-        Level.ALL,
-        Level.DEBUG,
-        Level.ERROR,
-        Level.FATAL,
-        Level.INFO,
-        Level.OFF,
-        Level.WARN
-    })));
-
-    // Button-Aktionen
-    refreshButton.addActionListener( new ActionListener() {
-      public void actionPerformed(ActionEvent e) {
-        refresh();
-      }
-    });
-    reloadButton.addActionListener( new ActionListener() {
-      public void actionPerformed(ActionEvent e) {
-        reload();
-      }
-    });
-
-    // Componenten in GUI einbinden
-    this.getContentPane().add( reloadButton,                   new GridBagConstraints(0,0,1,1,0.0,0.0,GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(5,5,5,5),0,0) );
-    this.getContentPane().add( configFileField,                new GridBagConstraints(1,0,1,1,1.0,0.0,GridBagConstraints.WEST,GridBagConstraints.HORIZONTAL,new Insets(5,5,5,5),0,0) );
-    this.getContentPane().add( new JScrollPane( loggerTable ), new GridBagConstraints(0,1,2,1,1.0,1.0,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(5,5,5,5),0,0) );
-    this.getContentPane().add( refreshButton,                  new GridBagConstraints(0,2,1,1,0.0,0.0,GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(5,5,5,5),0,0) );
-  }
-
-  /**
-   * Aktualisiert die Logger auf Basis der Konfigurationsdatei. Dies entspricht
-   * der Aktion des {@linkplain #reloadButton Reload-Button}.
-   */
-  public void reload() {
-    if ( loggerTableModel != null && configFileField.getValue() != null ) {
-      try {
-        String configFileName = configFileField.getValue().getAbsolutePath();
-        PropertyConfigurator.configure(configFileName);
-        refresh();
-      } catch (Exception err) {
-        ExceptionDialog.show(this,err);
-      }
-    }
-  }
-
-  /**
-   * Aktualisiert die Logger-Tabelle auf Basis der aktuelle geladenen
-   * Log4j-Logger.  Dies entspricht der Aktion des
-   * {@linkplain #refreshButton Refresh-Button}.
-   * @see LoggerConfigurationTableModel#refresh()
-   */
-  public void refresh() {
-    if ( loggerTableModel != null ) {
-      loggerTableModel.refresh();
-    }
-  }
-
-  /**
-   * Liefert einen String, der die {@link Appender} eines Loggers darstellt.
-   * <ul>
-   *   <li>{@link FileAppender} werden durch den Dateinamen dargestellt</li>
-   *   <li>{@link ConsoleAppender} werden durch das Schluesselwort "CONSOLE" dargestellt</li>
-   *   <li>Alle anderen {@link Appender} werden NICHT dargestellt</li>
-   * </ul>
-   * Sub-Klassen koennen diese Methode ueberschreiben, um auch andere
-   * Appender-Arten darzustellen.
-   * @param appenders {@link Appender}-Liste
-   */
-  public String getStringFromAppenders(Enumeration<Appender> appenders) {
-    StringBuffer buffer = new StringBuffer();
-    for(;appenders != null && appenders.hasMoreElements();) {
-      Appender appender = appenders.nextElement();
-      if ( appender instanceof ConsoleAppender )
-        buffer.append("CONSOLE");
-      if ( appender instanceof FileAppender )
-        buffer.append( ((FileAppender)appender).getFile() );
-      if ( appenders.hasMoreElements() )
-        buffer.append("; ");
-    }
-    return buffer.toString();
-  }
-
-//    /**
-//     * Ermittelt  einen String, der die {@link Appender} eines Loggers darstellt.
-//     * {@link FileAppender} werden durch den Dateinamen dargestellt und
-//     * {@link ConsoleAppender} durch das Schluesselwort "CONSOLE".
-//     * @param appenders {@link Appender}-Liste
-//     */
-//    private void setAppendersFromString(String appendersStr, Logger logger) {
-//      logger.removeAllAppenders();
-//      StringTokenizer tok = new StringTokenizer(appendersStr);
-//      for(;tok.hasMoreTokens();) {
-//        String appenderStr = tok.nextToken(" ;\t\n");
-//        Appender appender = null;
-//        if ( appenderStr.equalsIgnoreCase("CONSOLE") )
-//          appender = new ConsoleAppender();
-//        else {
-//          appender = new RollingFileAppender();
-//          ((RollingFileAppender)appender).setFile(appenderStr);
-//        }
-//        logger.addAppender( appender );
-//      }
-//    }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing.log4j;
+
+import java.awt.Component;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.File;
+import java.util.Enumeration;
+
+import javax.swing.DefaultCellEditor;
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JFrame;
+import javax.swing.JScrollPane;
+import javax.swing.JTable;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.ConsoleAppender;
+import org.apache.log4j.FileAppender;
+import org.apache.log4j.Level;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+import org.apache.log4j.PropertyConfigurator;
+import org.apache.log4j.spi.LoggerRepository;
+
+import schmitzm.swing.ExceptionDialog;
+import schmitzm.swing.FileInputOption;
+import schmitzm.swing.SwingUtil;
+import schmitzm.swing.table.ComponentRenderer;
+
+/**
+ * Diese Klasse stellt ein Fenster dar, in dem die aktuell im {@link LogManager}
+ * registrierten Log4j-Logger als Tabelle dargestellt sind.
+ * <ol>
+ *   <li>Logger-Name</li>
+ *   <li>Level</li>
+ *   <li>Additivitaet (ob rekursiv auch die Vater-Appender ausgefuehrt werden)</li>
+ *   <li>Dateinamen der {@link FileAppender}, "CONSOLE" fuer {@link ConsoleAppender}</li>
+ * </ol>
+ * Ueber einen {@linkplain #refresh() Refresh-Button} kann die Tabelle jederzeit aktualisiert
+ * werden. Es koennen <b>keine</b> Logger hinzugefuegt oder entfernt werden.
+ * Veraendert werden koennen die Logger nur hinsichtlich ihres Levels und ihrer
+ * Addititvitaet.<br>
+ * Die Eingabe-Maske bietet jedoch die Moeglichkeit, eine Logger-Konfiguration
+ * aus einer {@linkplain PropertyConfigurator#doConfigure(String,LoggerRepository) Log4j-Konfigurationsdatei}
+ * (neu) zu laden.<br>
+ * <b><u>Beachte</u>:</b><br>
+ * Beim Neu-Laden werden lediglich die <u>explizit</u> in der Datei spezifizierten
+ * Logger-Konfigurationen aktualisiert. Vom der Applikation erzeugte Logger bleiben
+ * erhalten (und koennen auch nicht mehr geloescht werden)!
+ * Ebenso bleiben alle Logger-Properties unveraendert erhalten, die nicht
+ * <u>explizit</u> in der Konfigurationsdatei angegeben sind. Wird z.B. die
+ * Additivitaet eines Loggers in der Datei nicht gesetzt, wird sie beim ersten
+ * Einlesen per Default auf {@code true} gesetzt. Wird sie durch den Anwender
+ * abgeaendert, bleibt diese Einstellung erhalten, auch wenn die Datei neu
+ * eingelesen wird.
+ * @see LoggerConfigurationTableModel
+ * @see Logger
+ * @see LogManager
+ * @see PropertyConfigurator#configure(String)
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class LoggerFrame extends JFrame {
+  /** Eingabe-Feld fuer die Log4j-Konfigurationsdatei. */
+  protected FileInputOption configFileField =  new FileInputOption(null,false);
+  /** Butten, ueber den die Log4j-Konfigurationsdatei neu geladen wird.
+   *  @see #reload() */
+  protected JButton reloadButton = new JButton( SwingUtil.RESOURCE.getString("Reload") );
+  /** Butten, ueber den die Logger-Tabelle aktualisiert wird.
+   *  @see #refresh() */
+  protected JButton refreshButton = new JButton( SwingUtil.RESOURCE.getString("Refresh") );
+  /** Tabelle, in der die Logger angezeigt werden.
+   *  @see #loggerTableModel */
+  protected JTable loggerTable = null;
+  /** Datenbasis fuer die Logger-Tabelle. */
+  protected LoggerConfigurationTableModel loggerTableModel = null;
+
+  /**
+   * Erzeugt ein neues Fenster.
+   * @param file vorgeblendete Log4j-Konfigurationsdatei
+   */
+  public LoggerFrame(File file) {
+    super("Log4j Logger configuration");
+    initGUI();
+    configFileField.setValue(file);
+  }
+
+  /**
+   * Erzeugt ein neues Fenster.
+   */
+  public LoggerFrame() {
+    this(null);
+  }
+
+  /**
+   * Initialisiert das Fenster-Layout.
+   */
+  protected void initGUI() {
+    this.setLayout( new GridBagLayout() );
+    this.setSize(400,300);
+    // Logger-Tabelle
+    loggerTableModel = new LoggerConfigurationTableModel();
+    loggerTable = new JTable(loggerTableModel);
+    loggerTable.setCellSelectionEnabled(false);
+    loggerTable.setRowHeight( new JComboBox().getPreferredSize().height );
+    loggerTable.setDefaultRenderer( Enumeration.class, new ComponentRenderer() {
+      public Component createRendererComponent( JTable table,
+                                                Object value,
+                                                boolean isSelected,
+                                                boolean hasFocus,
+                                                int row,
+                                                int column) {
+
+        // Appender in String umwandeln
+        if ( value instanceof Enumeration )
+          value = getStringFromAppenders((Enumeration<Appender>)value);
+        return super.createRendererComponent(table,value,isSelected,hasFocus,row,column);
+      }
+    });
+    loggerTable.setDefaultRenderer( Boolean.class, new ComponentRenderer.JCheckBox());
+    loggerTable.setDefaultEditor( Boolean.class, new DefaultCellEditor( new JCheckBox() {
+      public int getHorizontalAlignment() {
+        return this.CENTER;
+      }
+      public int getVerticalAlignment() {
+        return this.CENTER;
+      }
+    }));
+
+    loggerTable.setDefaultRenderer( Level.class, new ComponentRenderer.JComboBox() );
+    loggerTable.setDefaultEditor( Level.class, new DefaultCellEditor( new JComboBox( new Object[] {
+        Level.ALL,
+        Level.DEBUG,
+        Level.ERROR,
+        Level.FATAL,
+        Level.INFO,
+        Level.OFF,
+        Level.WARN
+    })));
+
+    // Button-Aktionen
+    refreshButton.addActionListener( new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        refresh();
+      }
+    });
+    reloadButton.addActionListener( new ActionListener() {
+      public void actionPerformed(ActionEvent e) {
+        reload();
+      }
+    });
+
+    // Componenten in GUI einbinden
+    this.getContentPane().add( reloadButton,                   new GridBagConstraints(0,0,1,1,0.0,0.0,GridBagConstraints.WEST,GridBagConstraints.NONE,new Insets(5,5,5,5),0,0) );
+    this.getContentPane().add( configFileField,                new GridBagConstraints(1,0,1,1,1.0,0.0,GridBagConstraints.WEST,GridBagConstraints.HORIZONTAL,new Insets(5,5,5,5),0,0) );
+    this.getContentPane().add( new JScrollPane( loggerTable ), new GridBagConstraints(0,1,2,1,1.0,1.0,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(5,5,5,5),0,0) );
+    this.getContentPane().add( refreshButton,                  new GridBagConstraints(0,2,1,1,0.0,0.0,GridBagConstraints.EAST,GridBagConstraints.NONE,new Insets(5,5,5,5),0,0) );
+  }
+
+  /**
+   * Aktualisiert die Logger auf Basis der Konfigurationsdatei. Dies entspricht
+   * der Aktion des {@linkplain #reloadButton Reload-Button}.
+   */
+  public void reload() {
+    if ( loggerTableModel != null && configFileField.getValue() != null ) {
+      try {
+        String configFileName = configFileField.getValue().getAbsolutePath();
+        PropertyConfigurator.configure(configFileName);
+        refresh();
+      } catch (Exception err) {
+        ExceptionDialog.show(this,err);
+      }
+    }
+  }
+
+  /**
+   * Aktualisiert die Logger-Tabelle auf Basis der aktuelle geladenen
+   * Log4j-Logger.  Dies entspricht der Aktion des
+   * {@linkplain #refreshButton Refresh-Button}.
+   * @see LoggerConfigurationTableModel#refresh()
+   */
+  public void refresh() {
+    if ( loggerTableModel != null ) {
+      loggerTableModel.refresh();
+    }
+  }
+
+  /**
+   * Liefert einen String, der die {@link Appender} eines Loggers darstellt.
+   * <ul>
+   *   <li>{@link FileAppender} werden durch den Dateinamen dargestellt</li>
+   *   <li>{@link ConsoleAppender} werden durch das Schluesselwort "CONSOLE" dargestellt</li>
+   *   <li>Alle anderen {@link Appender} werden NICHT dargestellt</li>
+   * </ul>
+   * Sub-Klassen koennen diese Methode ueberschreiben, um auch andere
+   * Appender-Arten darzustellen.
+   * @param appenders {@link Appender}-Liste
+   */
+  public String getStringFromAppenders(Enumeration<Appender> appenders) {
+    StringBuffer buffer = new StringBuffer();
+    for(;appenders != null && appenders.hasMoreElements();) {
+      Appender appender = appenders.nextElement();
+      if ( appender instanceof ConsoleAppender )
+        buffer.append("CONSOLE");
+      if ( appender instanceof FileAppender )
+        buffer.append( ((FileAppender)appender).getFile() );
+      if ( appenders.hasMoreElements() )
+        buffer.append("; ");
+    }
+    return buffer.toString();
+  }
+
+//    /**
+//     * Ermittelt  einen String, der die {@link Appender} eines Loggers darstellt.
+//     * {@link FileAppender} werden durch den Dateinamen dargestellt und
+//     * {@link ConsoleAppender} durch das Schluesselwort "CONSOLE".
+//     * @param appenders {@link Appender}-Liste
+//     */
+//    private void setAppendersFromString(String appendersStr, Logger logger) {
+//      logger.removeAllAppenders();
+//      StringTokenizer tok = new StringTokenizer(appendersStr);
+//      for(;tok.hasMoreTokens();) {
+//        String appenderStr = tok.nextToken(" ;\t\n");
+//        Appender appender = null;
+//        if ( appenderStr.equalsIgnoreCase("CONSOLE") )
+//          appender = new ConsoleAppender();
+//        else {
+//          appender = new RollingFileAppender();
+//          ((RollingFileAppender)appender).setFile(appenderStr);
+//        }
+//        logger.addAppender( appender );
+//      }
+//    }
+}

Modified: trunk/src/schmitzm/swing/menu/ActionStructure.java
===================================================================
--- trunk/src/schmitzm/swing/menu/ActionStructure.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/menu/ActionStructure.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,58 +1,76 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing.menu;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+/**
+ * Diese Klasse repraesentiert eine Kette von Aktionen. Jede Aktion wird
+ * durch einen <code>int</code>-Wert codiert. Alle Aktionen der Kette zusammen
+ * muessen ebenfalls in einem <code>int</code>-Wert codiert werden koennen.
+ * Eine Moeglichkeit ist z.B. die logische Veroderung der einzelnen Aktionen, wenn
+ * jede Einzelaktion durch eine 2er-Potenz codiert wird.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public interface ActionStructure {
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+  /**
+   * Aktion, die fuer "keine Aktion" steht.
+   */
+  public static final int ACTION_NONE = 0;
 
-package schmitzm.swing.menu;
-
-/**
- * Diese Klasse repraesentiert eine Kette von Aktionen. Jede Aktion wird
- * durch einen <code>int</code>-Wert codiert. Alle Aktionen der Kette zusammen
- * muessen ebenfalls in einem <code>int</code>-Wert codiert werden koennen.
- * Eine Moeglichkeit ist z.B. die logische Veroderung der einzelnen Aktionen, wenn
- * jede Einzelaktion durch eine 2er-Potenz codiert wird.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public interface ActionStructure {
-
-  /**
-   * Aktion, die fuer "keine Aktion" steht.
-   */
-  public static final int ACTION_NONE = 0;
-
-  /**
-   * Liefert das <code>ActionStructure</code>-Element, das in der
-   * Kette unmittelbar uebergeordnet ist.
-   * @return <code>null</code> falls die Aktion die Wurzel-Aktion darstellt
-   */
-  public ActionStructure getParentActionStructure();
-
-  /**
-   * Liefert die Aktion, fuer die dieses Element in der
-   * <code>ActionStructure</code>-Kette steht.
-   */
-  public int getActionCode();
-
-  /**
-   * Liefert einen Wert, der saemtliche Aktionen der
-   * <code>ActionStructure</code>-Kette codiert. z.B. logische Veroderung der
-   * einzelnen Aktionen der <code>ActionStructure</code>-Kette.
-   */
-  public int getCompleteActionCode();
-
-  /**
-   * Prueft, ob zwei Actionscodes gemeinsame Komponenten beinhalten.
-   * @param actionCode1 Aktionscode
-   * @param actionCode2 Aktionscode
-   * @return <code>true</code> gdw. die beiden Gesamt-Aktionen mindestens
-   *         eine gemeinsame Aktion haben.
-   */
-  public boolean compareActions(int actionCode1, int actionCode2);
-}
+  /**
+   * Liefert das <code>ActionStructure</code>-Element, das in der
+   * Kette unmittelbar uebergeordnet ist.
+   * @return <code>null</code> falls die Aktion die Wurzel-Aktion darstellt
+   */
+  public ActionStructure getParentActionStructure();
+
+  /**
+   * Liefert die Aktion, fuer die dieses Element in der
+   * <code>ActionStructure</code>-Kette steht.
+   */
+  public int getActionCode();
+
+  /**
+   * Liefert einen Wert, der saemtliche Aktionen der
+   * <code>ActionStructure</code>-Kette codiert. z.B. logische Veroderung der
+   * einzelnen Aktionen der <code>ActionStructure</code>-Kette.
+   */
+  public int getCompleteActionCode();
+
+  /**
+   * Prueft, ob zwei Actionscodes gemeinsame Komponenten beinhalten.
+   * @param actionCode1 Aktionscode
+   * @param actionCode2 Aktionscode
+   * @return <code>true</code> gdw. die beiden Gesamt-Aktionen mindestens
+   *         eine gemeinsame Aktion haben.
+   */
+  public boolean compareActions(int actionCode1, int actionCode2);
+}

Modified: trunk/src/schmitzm/swing/menu/ConnectedPopupMenu.java
===================================================================
--- trunk/src/schmitzm/swing/menu/ConnectedPopupMenu.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/menu/ConnectedPopupMenu.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,169 +1,188 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.swing.menu;
-
-import java.awt.Component;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseListener;
-import java.util.Vector;
-
-import javax.swing.JMenuItem;
-import javax.swing.JPopupMenu;
-
-/**
- * <hr>
- * <small><i>Diese Klasse wurde urspruenglich 2002/2003 von <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- *            fuer die ADAGIOS-Java-Library (Universitaet Bonn) erstellt, 2009 in das
- *            SCHMITZM-Projekt uebernommen und teilweise erweitert.</i></small>
- * <hr>
- * Diese Klasse erweitert das <code>JPopupMenu</code>.
- * Menueeintraege (Instanzen von <code>JMenuItem</code>) werden automatisch
- * in der <code>add(String)</code>-Methode erzeugt und dem Menue hinzugefuegt.
- * Es muss nicht jedem Menueeintragen einzeln ein eigener <code>ActionListener</code>
- * hinzugefuegt werden, um auf eine Aktion zu reagieren. Das
- * <code>ConnectedPopupMenu</code> selbst "achtet" auf eine Aktion und
- * informiert ueber <b>einen</b> <code>ActionListener</code> die verbundenen
- * Anwendungen. In deren <code>actionPerformed(..)</code>-Methode kann die
- * Anwendung ueber <code>getProcessedItem()</code> ermittelt werden, welcher
- * Menueeintrag gewaehlt wurde.
- * @see javax.swing.JPopupMenu
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- */
-public class ConnectedPopupMenu extends JPopupMenu implements MouseListener, ActionListener {
-  private Object popupClickSource = null;
-  private Vector listeners        = new Vector();
-  private int    processedItem    = -1;
-
-  /**
-   * Fuegt dem Menue einen <code>ActionListener</code> hinzu.
-   * Dieser wird informiert, sobald ein Menueeintrag des PopupMenue
-   * ausgewaehlt wurde.
-   */
-  public void addActionListener(ActionListener listener) {
-    listeners.add( listener );
-  }
-
-  /**
-   * Entfernt einen <code>ActionListener</code>.
-   */
-  public void removeActionListener(ActionListener listener) {
-    listeners.remove( listener );
-  }
-
-  /**
-   * Wird aufgerufen, sobald eine Maustaste auf einer mit dem Menue
-   * verbundene Komponente gedrueckt wurde.
-   * Die Methode checkt, ob es sich bei dem Klick um einen PopupTrigger
-   * (i.A. Rechtsklick) handelt.
-   * Ist dies der Fall, wird das PopupMenue geoeffnet.
-   */
-  public void mousePressed(MouseEvent e) {
-    checkPopupSignal(e);
-  }
-
-  /**
-   * Wird aufgerufen, sobald eine Maustaste auf einer mit dem Menue
-   * verbundene Komponente losgelassen wurde.
-   * Die Methode checkt, ob es sich bei dem Loslassen um einen PopupTrigger
-   * (i.A. Rechtsklick) handelt.
-   * Ist dies der Fall, wird das PopupMenue geoeffnet.
-   */
-  public void mouseReleased(MouseEvent e) {
-    checkPopupSignal(e);
-  }
-
-  /**
-   * Checkt, ob ein PopupTrigger (i.A. Rechtsklick) auf eine mit dem
-   * PopupMenue verbundene Komponente stattgefunden hat.
-   * Ist dies der Fall, wird das PopupMenue geoeffnet.
-   */
-  private void checkPopupSignal(MouseEvent e) {
-    if ( e.isPopupTrigger() ) {
-      this.show( (Component)e.getSource(), e.getX(), e.getY() );
-      popupClickSource = e.getSource();
-      e.consume();
-    }
-  }
-
-  /**
-   * Liefert den Index des Menueeintrags, der ausgewaehlt wurde.
-   * Ist nur zugaenglich, waehrend ein <code>ActionListerner</code> ueber
-   * die Auswahl eines Menueeintrags informiert wird!! Zu allen anderen
-   * Zeitpunkten liefert diese Methode -1.
-   */
-  public int getProcessedItem() {
-    return processedItem;
-  }
-
-  /**
-   * Checkt, auf welchen Menueeintrag geklickt wurde und informiert die
-   * angeschlossenen <code>ActionListener</code> ueber das Ereignis.<br>
-   * Diese koennen (in ihrer <code>actionPerformed</code>-Methode ueber die
-   * Methode <code>getProcessedItem()</code> ermitteln, auf welchen
-   * Menueeintrag geklickt wurde.<br>
-   * Das an die <code>ActionListener</code> weiter gereichte
-   * <code>ActionEvent</code> erhaelt als Quelle (<code>getSource()</code>)
-   * dasjenige Objekt, auf dem das PopupMenue (mittels Linksklick)
-   * geoeffnet wurde (nicht das <code>ConnectedPopupMenu</code>!!)
-   * @see #addMouseListener(MouseListener)
-   */
-  public void actionPerformed(ActionEvent e) {
-    // herausfinden, weches Menueitem geklickt wurde
-    for (int i=0; i<this.getComponentCount(); i++) {
-      if ( this.getComponent(i) == e.getSource() ) {
-        processedItem = i;
-        for (int j=0; j<listeners.size(); j++)
-          ((ActionListener)listeners.elementAt(j)).actionPerformed( new ActionEvent( popupClickSource, e.getID(), "" ) );
-        processedItem = -1;
-        break;
-      }
-    }
-  }
-
-  /**
-   * Verbindet das Popup-Menue mit einer Komponente.
-   * Beim (Rechts-)Klick auf diese Komponente wird das Popup-Menue geoeffnet.
-   */
-  public void connectTo(Component comp) {
-    comp.addMouseListener(this);
-  }
-
-  /**
-   * Erzeugt einen Menueeintrag und fuegt ihn dem Menue hinzu.
-   * Als <code>ActionListener</code> fuer den Menueeintrag wird die
-   * <code>ConnectedPopupMenue</code>-Instanz selbst verwendet, welcher
-   * wiederum die angeschlossenen <code>ActionListener</code> informiert.
-   * @param desc Beschreibung fuer den Menueeintrag
-   * @see #actionPerformed(ActionEvent)
-   */
-  public JMenuItem add(String desc) {
-    JMenuItem item = super.add(desc);
-    item.addActionListener(this);
-    return item;
-  }
-
-  /**
-   * Implementiert nichts.
-   */
-  public void mouseClicked(MouseEvent e) {}
-
-  /**
-   * Implementiert nichts.
-   */
-  public void mouseEntered(MouseEvent e) {}
-
-  /**
-   * Implementiert nichts.
-   */
-  public void mouseExited(MouseEvent e) {}
-}
\ No newline at end of file
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing.menu;
+
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import java.util.Vector;
+
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+
+/**
+ * <hr>
+ * <small><i>Diese Klasse wurde urspruenglich 2002/2003 von <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *            fuer die ADAGIOS-Java-Library (Universitaet Bonn) erstellt, 2009 in das
+ *            SCHMITZM-Projekt uebernommen und teilweise erweitert.</i></small>
+ * <hr>
+ * Diese Klasse erweitert das <code>JPopupMenu</code>.
+ * Menueeintraege (Instanzen von <code>JMenuItem</code>) werden automatisch
+ * in der <code>add(String)</code>-Methode erzeugt und dem Menue hinzugefuegt.
+ * Es muss nicht jedem Menueeintragen einzeln ein eigener <code>ActionListener</code>
+ * hinzugefuegt werden, um auf eine Aktion zu reagieren. Das
+ * <code>ConnectedPopupMenu</code> selbst "achtet" auf eine Aktion und
+ * informiert ueber <b>einen</b> <code>ActionListener</code> die verbundenen
+ * Anwendungen. In deren <code>actionPerformed(..)</code>-Methode kann die
+ * Anwendung ueber <code>getProcessedItem()</code> ermittelt werden, welcher
+ * Menueeintrag gewaehlt wurde.
+ * @see javax.swing.JPopupMenu
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ */
+public class ConnectedPopupMenu extends JPopupMenu implements MouseListener, ActionListener {
+  private Object popupClickSource = null;
+  private Vector listeners        = new Vector();
+  private int    processedItem    = -1;
+
+  /**
+   * Fuegt dem Menue einen <code>ActionListener</code> hinzu.
+   * Dieser wird informiert, sobald ein Menueeintrag des PopupMenue
+   * ausgewaehlt wurde.
+   */
+  public void addActionListener(ActionListener listener) {
+    listeners.add( listener );
+  }
+
+  /**
+   * Entfernt einen <code>ActionListener</code>.
+   */
+  public void removeActionListener(ActionListener listener) {
+    listeners.remove( listener );
+  }
+
+  /**
+   * Wird aufgerufen, sobald eine Maustaste auf einer mit dem Menue
+   * verbundene Komponente gedrueckt wurde.
+   * Die Methode checkt, ob es sich bei dem Klick um einen PopupTrigger
+   * (i.A. Rechtsklick) handelt.
+   * Ist dies der Fall, wird das PopupMenue geoeffnet.
+   */
+  public void mousePressed(MouseEvent e) {
+    checkPopupSignal(e);
+  }
+
+  /**
+   * Wird aufgerufen, sobald eine Maustaste auf einer mit dem Menue
+   * verbundene Komponente losgelassen wurde.
+   * Die Methode checkt, ob es sich bei dem Loslassen um einen PopupTrigger
+   * (i.A. Rechtsklick) handelt.
+   * Ist dies der Fall, wird das PopupMenue geoeffnet.
+   */
+  public void mouseReleased(MouseEvent e) {
+    checkPopupSignal(e);
+  }
+
+  /**
+   * Checkt, ob ein PopupTrigger (i.A. Rechtsklick) auf eine mit dem
+   * PopupMenue verbundene Komponente stattgefunden hat.
+   * Ist dies der Fall, wird das PopupMenue geoeffnet.
+   */
+  private void checkPopupSignal(MouseEvent e) {
+    if ( e.isPopupTrigger() ) {
+      this.show( (Component)e.getSource(), e.getX(), e.getY() );
+      popupClickSource = e.getSource();
+      e.consume();
+    }
+  }
+
+  /**
+   * Liefert den Index des Menueeintrags, der ausgewaehlt wurde.
+   * Ist nur zugaenglich, waehrend ein <code>ActionListerner</code> ueber
+   * die Auswahl eines Menueeintrags informiert wird!! Zu allen anderen
+   * Zeitpunkten liefert diese Methode -1.
+   */
+  public int getProcessedItem() {
+    return processedItem;
+  }
+
+  /**
+   * Checkt, auf welchen Menueeintrag geklickt wurde und informiert die
+   * angeschlossenen <code>ActionListener</code> ueber das Ereignis.<br>
+   * Diese koennen (in ihrer <code>actionPerformed</code>-Methode ueber die
+   * Methode <code>getProcessedItem()</code> ermitteln, auf welchen
+   * Menueeintrag geklickt wurde.<br>
+   * Das an die <code>ActionListener</code> weiter gereichte
+   * <code>ActionEvent</code> erhaelt als Quelle (<code>getSource()</code>)
+   * dasjenige Objekt, auf dem das PopupMenue (mittels Linksklick)
+   * geoeffnet wurde (nicht das <code>ConnectedPopupMenu</code>!!)
+   * @see #addMouseListener(MouseListener)
+   */
+  public void actionPerformed(ActionEvent e) {
+    // herausfinden, weches Menueitem geklickt wurde
+    for (int i=0; i<this.getComponentCount(); i++) {
+      if ( this.getComponent(i) == e.getSource() ) {
+        processedItem = i;
+        for (int j=0; j<listeners.size(); j++)
+          ((ActionListener)listeners.elementAt(j)).actionPerformed( new ActionEvent( popupClickSource, e.getID(), "" ) );
+        processedItem = -1;
+        break;
+      }
+    }
+  }
+
+  /**
+   * Verbindet das Popup-Menue mit einer Komponente.
+   * Beim (Rechts-)Klick auf diese Komponente wird das Popup-Menue geoeffnet.
+   */
+  public void connectTo(Component comp) {
+    comp.addMouseListener(this);
+  }
+
+  /**
+   * Erzeugt einen Menueeintrag und fuegt ihn dem Menue hinzu.
+   * Als <code>ActionListener</code> fuer den Menueeintrag wird die
+   * <code>ConnectedPopupMenue</code>-Instanz selbst verwendet, welcher
+   * wiederum die angeschlossenen <code>ActionListener</code> informiert.
+   * @param desc Beschreibung fuer den Menueeintrag
+   * @see #actionPerformed(ActionEvent)
+   */
+  public JMenuItem add(String desc) {
+    JMenuItem item = super.add(desc);
+    item.addActionListener(this);
+    return item;
+  }
+
+  /**
+   * Implementiert nichts.
+   */
+  public void mouseClicked(MouseEvent e) {}
+
+  /**
+   * Implementiert nichts.
+   */
+  public void mouseEntered(MouseEvent e) {}
+
+  /**
+   * Implementiert nichts.
+   */
+  public void mouseExited(MouseEvent e) {}
+}

Modified: trunk/src/schmitzm/swing/menu/ObjectMenuItem.java
===================================================================
--- trunk/src/schmitzm/swing/menu/ObjectMenuItem.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/menu/ObjectMenuItem.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,116 +1,134 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing.menu;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+import java.awt.event.ActionListener;
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+import javax.swing.JMenuItem;
 
-package schmitzm.swing.menu;
-
-import java.awt.event.ActionListener;
+/**
+ * Diese Klasse stellt einen Menupunkt dar, der gleichzeitig auch ein
+ * Benutzer-Objekt beinhalten kann.<br>
+ * Jedem Menuepunkt ist ein ActionCode zugeordnet, so dass nach Auswahl des
+ * Menuepunkts eine Aktionskette entsteht, welche in einem einheitlichen
+ * <code>ActionListener</code> interpretiert werden kann.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class ObjectMenuItem extends JMenuItem implements ActionStructure {
+  private   int               actionCode = 0;
+  private   ActionStructure   parent;
+  private   Object            object;
 
-import javax.swing.JMenuItem;
-
-/**
- * Diese Klasse stellt einen Menupunkt dar, der gleichzeitig auch ein
- * Benutzer-Objekt beinhalten kann.<br>
- * Jedem Menuepunkt ist ein ActionCode zugeordnet, so dass nach Auswahl des
- * Menuepunkts eine Aktionskette entsteht, welche in einem einheitlichen
- * <code>ActionListener</code> interpretiert werden kann.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class ObjectMenuItem extends JMenuItem implements ActionStructure {
-  private   int               actionCode = 0;
-  private   ActionStructure   parent;
-  private   Object            object;
-
-  /**
-   * Erzeugt einen neuen Menuepunkt.
-   * @param name       Anzeige-Name
-   * @param object     Benutzerobjekt
-   * @param actionCode codiert die Aktion die mit diesem Menue verknuepft ist
-   * @param parent     uebergeordnete Aktion (z.B. uebergeordnetes <code>ObjectSubMenu</code>)
-   */
-  public ObjectMenuItem(String name, Object object, int actionCode, ActionStructure parent) {
-    super(name);
-    this.parent     = parent;
-    this.actionCode = actionCode;
-    this.object     = object;
-  }
-
-  /**
-   * Erzeugt einen neuen Menuepunkt. Diesem ist keine spezielle Aktion
-   * zugeordnet.
-   * @param name    Anzeige-Name
-   * @param object  Benutzerobjekt
-   * @param parent  uebergeordnete Aktion (z.B. uebergeordnetes <code>ObjectSubMenu</code>)
-   * @see schmitzm.swing.menu.ActionStructure#ACTION_NONE
-   */
-  public ObjectMenuItem(String name, Object object, ActionStructure parent) {
-    this(name,object,ACTION_NONE,parent);
-  }
-
-  /**
-   * Erzeugt einen neuen Menuepunkt. Diesem ist kein Objekt zugeordnet, sondern
-   * nur eine Aktion.
-   * @param name       Anzeige-Name
-   * @param listener   Listener, der auf den Menuepunkt horcht
-   * @param actionCode codiert die Aktion die mit diesem Menue verknuepft ist
-   * @param parent     uebergeordnete Aktion (z.B. uebergeordnetes <code>ObjectSubMenu</code>)
-   */
-  public ObjectMenuItem(String name, ActionListener listener, int actionCode, ActionStructure parent) {
-    this(name,(Object)null,actionCode,parent);
-    this.addActionListener(listener);
-  }
-
-
-  /**
-   * Liefert das Benutzer-Objekt des Menupunkts.
-   */
-  public Object getObject() {
-    return object;
-  }
-
-  /**
-   * Liefert die dem Menue uebergeordnete <code>ActionStructure</code>.
-   */
-  public ActionStructure getParentActionStructure() {
-    return parent;
-  }
-
-  /**
-   * Liefert die einzelne Aktion, die diesem Menue zugeordnet ist.
-   */
-  public int getActionCode() {
-    return actionCode;
-  }
-
-  /**
-   * Liefert die gesamte Aktionskette, die diesem Menue zugeordnet ist, in dem
-   * die einzelnen Aktionen der Kette logisch verodert werden.
-   */
-  public int getCompleteActionCode() {
-    if ( parent == null )
-      return getActionCode();
-    return getActionCode() | getParentActionStructure().getCompleteActionCode();
-  }
-
-  /**
-   * Prueft, ob zwei Actionscodes gemeinsame Komponenten beinhalten.
-   * Dies geschiet durch ein logisches UND zwischen den Aktionen, sowie
-   * einem Vergleich, ob das Ergebnis >0 ist.
-   * @param actionCode1 Aktionscode
-   * @param actionCode2 Aktionscode
-   * @return <code>true</code> gdw. die beiden Gesamt-Aktionen mindestens
-   *         eine gemeinsame Aktion haben.
-   */
-  public boolean compareActions(int actionCode1, int actionCode2) {
-    return (actionCode1 & actionCode2) > 0;
-  }
-
-}
+  /**
+   * Erzeugt einen neuen Menuepunkt.
+   * @param name       Anzeige-Name
+   * @param object     Benutzerobjekt
+   * @param actionCode codiert die Aktion die mit diesem Menue verknuepft ist
+   * @param parent     uebergeordnete Aktion (z.B. uebergeordnetes <code>ObjectSubMenu</code>)
+   */
+  public ObjectMenuItem(String name, Object object, int actionCode, ActionStructure parent) {
+    super(name);
+    this.parent     = parent;
+    this.actionCode = actionCode;
+    this.object     = object;
+  }
+
+  /**
+   * Erzeugt einen neuen Menuepunkt. Diesem ist keine spezielle Aktion
+   * zugeordnet.
+   * @param name    Anzeige-Name
+   * @param object  Benutzerobjekt
+   * @param parent  uebergeordnete Aktion (z.B. uebergeordnetes <code>ObjectSubMenu</code>)
+   * @see schmitzm.swing.menu.ActionStructure#ACTION_NONE
+   */
+  public ObjectMenuItem(String name, Object object, ActionStructure parent) {
+    this(name,object,ACTION_NONE,parent);
+  }
+
+  /**
+   * Erzeugt einen neuen Menuepunkt. Diesem ist kein Objekt zugeordnet, sondern
+   * nur eine Aktion.
+   * @param name       Anzeige-Name
+   * @param listener   Listener, der auf den Menuepunkt horcht
+   * @param actionCode codiert die Aktion die mit diesem Menue verknuepft ist
+   * @param parent     uebergeordnete Aktion (z.B. uebergeordnetes <code>ObjectSubMenu</code>)
+   */
+  public ObjectMenuItem(String name, ActionListener listener, int actionCode, ActionStructure parent) {
+    this(name,(Object)null,actionCode,parent);
+    this.addActionListener(listener);
+  }
+
+
+  /**
+   * Liefert das Benutzer-Objekt des Menupunkts.
+   */
+  public Object getObject() {
+    return object;
+  }
+
+  /**
+   * Liefert die dem Menue uebergeordnete <code>ActionStructure</code>.
+   */
+  public ActionStructure getParentActionStructure() {
+    return parent;
+  }
+
+  /**
+   * Liefert die einzelne Aktion, die diesem Menue zugeordnet ist.
+   */
+  public int getActionCode() {
+    return actionCode;
+  }
+
+  /**
+   * Liefert die gesamte Aktionskette, die diesem Menue zugeordnet ist, in dem
+   * die einzelnen Aktionen der Kette logisch verodert werden.
+   */
+  public int getCompleteActionCode() {
+    if ( parent == null )
+      return getActionCode();
+    return getActionCode() | getParentActionStructure().getCompleteActionCode();
+  }
+
+  /**
+   * Prueft, ob zwei Actionscodes gemeinsame Komponenten beinhalten.
+   * Dies geschiet durch ein logisches UND zwischen den Aktionen, sowie
+   * einem Vergleich, ob das Ergebnis >0 ist.
+   * @param actionCode1 Aktionscode
+   * @param actionCode2 Aktionscode
+   * @return <code>true</code> gdw. die beiden Gesamt-Aktionen mindestens
+   *         eine gemeinsame Aktion haben.
+   */
+  public boolean compareActions(int actionCode1, int actionCode2) {
+    return (actionCode1 & actionCode2) > 0;
+  }
+
+}

Modified: trunk/src/schmitzm/swing/menu/ObjectSubMenu.java
===================================================================
--- trunk/src/schmitzm/swing/menu/ObjectSubMenu.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/menu/ObjectSubMenu.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,123 +1,141 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing.menu;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+import java.awt.event.ActionListener;
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+import javax.swing.JMenu;
 
-package schmitzm.swing.menu;
-
-import java.awt.event.ActionListener;
+/**
+ * Diese Klasse stellt ein Untermenue in einer Menue-Struktur dar.<br>
+ * Jedem Menue ist ein ActionCode zugeordnet, so dass nach Auswahl eines
+ * Menuepunkts eine Aktionskette entsteht, welche in einem einheitlichen
+ * <code>ActionListener</code> interpretiert werden kann.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public abstract class ObjectSubMenu extends JMenu implements ActionStructure {
+  private    int              actionCode = 0;
+  private    ActionStructure  parent;
+  /** Speichert den (einheitlichen) <code>AktionListener</code>, der fuer
+   *  die Interpretation einer Menue-Auswahl verwendet wird. Dieser wird
+   *  einem <code>MenuItem</code> <b>nicht</b> automatisch zugeordnet!.
+   *  Die Speicherung in dieser abstrakten Oberklasse dient lediglich
+   *  der Handhabbarkeit der Unterklassen. */
+  protected  ActionListener   itemActionListener;
 
-import javax.swing.JMenu;
-
-/**
- * Diese Klasse stellt ein Untermenue in einer Menue-Struktur dar.<br>
- * Jedem Menue ist ein ActionCode zugeordnet, so dass nach Auswahl eines
- * Menuepunkts eine Aktionskette entsteht, welche in einem einheitlichen
- * <code>ActionListener</code> interpretiert werden kann.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public abstract class ObjectSubMenu extends JMenu implements ActionStructure {
-  private    int              actionCode = 0;
-  private    ActionStructure  parent;
-  /** Speichert den (einheitlichen) <code>AktionListener</code>, der fuer
-   *  die Interpretation einer Menue-Auswahl verwendet wird. Dieser wird
-   *  einem <code>MenuItem</code> <b>nicht</b> automatisch zugeordnet!.
-   *  Die Speicherung in dieser abstrakten Oberklasse dient lediglich
-   *  der Handhabbarkeit der Unterklassen. */
-  protected  ActionListener   itemActionListener;
-
-  /**
-   * Erzeugt ein neues Untermenue.
-   * @param name       Anzeige-Name fuer das Untermenue.
-   * @param actionCode codiert die Aktion die mit diesem Menue verknuepft ist
-   * @param parent     uebergeordnete Aktion (z.B. uebergeordnetes <code>ObjectSubMenu</code>)
-   * @param itemActionListener ActionListener, der fuer die Interpretation des
-   *                           ausgewaehlten Menuepunkts herangezogen wird (wird
-   *                           den Menuepunkten <b>nicht</b> automatisch zugeordnet!
-   * @param reorganize bestimmt, ob die Struktur dieses Menues bereits im Konstruktor
-   *                   erzeugt werden soll (siehe {@link #reorganize()}). In
-   *                   vielen Faellen wird diese Funktion manuell durch eine
-   *                   uebergeordnetes Menue ausgeloest, was eine
-   *                   Struktur-Erzeugung bei der Instanziierung ueberfluessig macht.
-   */
-  public ObjectSubMenu(String name, int actionCode, ActionStructure parent, ActionListener itemActionListener, boolean reorganize) {
-    super(name);
-    this.parent     = parent;
-    this.actionCode = actionCode;
-    this.itemActionListener = itemActionListener;
-    if (reorganize)
-      reorganize();
-  }
-
-  /**
-   * Erzeugt ein neues Wurzel-Menue. Diesem ist keine Aktion zugeordnet und
-   * es hat keine Uebergeordneten Menues. In der Regel ist es deshalb fuer
-   * die Interpretation und Verarbeitung der ausgewaehlten Menueaktion
-   * zustaendig (ist also selbst der <code>ActionListener</code>!).
-   * @param name Anzeige-Name fuer das Untermenue.
-   */
-  public ObjectSubMenu(String name) {
-    this(name,ActionStructure.ACTION_NONE,null,null,false);
-  }
-
-  /**
-   * Erstellt die Struktur des Menues neu und ruft <code>reorganize()</code>
-   * fuer alle Untermenues auf.
-   */
-  public void reorganize() {
-    for (int i = 0; i < getItemCount(); i++)
-      if ( getItem(i) instanceof ObjectSubMenu )
-        ((ObjectSubMenu)getItem(i)).reorganize();
-  }
-
-  /**
-   * Liefert den ActionListener, der den Menuepunkten zugeordnet werden kann.
-   */
-  public ActionListener getItemActionListener() {
-    return this.itemActionListener;
-  }
-
-  /**
-   * Liefert die dem Menue uebergeordnete <code>ActionStructure</code>.
-   */
-  public ActionStructure getParentActionStructure() {
-    return parent;
-  }
-
-  /**
-   * Liefert die einzelne Aktion, die diesem Menue zugeordnet ist.
-   */
-  public int getActionCode() {
-    return actionCode;
-  }
-
-  /**
-   * Liefert die gesamte Aktionskette, die diesem Menue zugeordnet ist, in dem
-   * die einzelnen Aktionen der Kette logisch verodert werden.
-   */
-  public int getCompleteActionCode() {
-    if ( parent == null )
-      return getActionCode();
-    return getActionCode() | getParentActionStructure().getCompleteActionCode();
-  }
-
-  /**
-   * Prueft, ob zwei Actionscodes gemeinsame Komponenten beinhalten.
-   * Dies geschiet durch ein logisches UND zwischen den Aktionen, sowie
-   * einem Vergleich, ob das Ergebnis >0 ist.
-   * @param actionCode1 Aktionscode
-   * @param actionCode2 Aktionscode
-   * @return <code>true</code> gdw. die beiden Gesamt-Aktionen mindestens
-   *         eine gemeinsame Aktion haben.
-   */
-  public boolean compareActions(int actionCode1, int actionCode2) {
-    return (actionCode1 & actionCode2) > 0;
-  }
-}
+  /**
+   * Erzeugt ein neues Untermenue.
+   * @param name       Anzeige-Name fuer das Untermenue.
+   * @param actionCode codiert die Aktion die mit diesem Menue verknuepft ist
+   * @param parent     uebergeordnete Aktion (z.B. uebergeordnetes <code>ObjectSubMenu</code>)
+   * @param itemActionListener ActionListener, der fuer die Interpretation des
+   *                           ausgewaehlten Menuepunkts herangezogen wird (wird
+   *                           den Menuepunkten <b>nicht</b> automatisch zugeordnet!
+   * @param reorganize bestimmt, ob die Struktur dieses Menues bereits im Konstruktor
+   *                   erzeugt werden soll (siehe {@link #reorganize()}). In
+   *                   vielen Faellen wird diese Funktion manuell durch eine
+   *                   uebergeordnetes Menue ausgeloest, was eine
+   *                   Struktur-Erzeugung bei der Instanziierung ueberfluessig macht.
+   */
+  public ObjectSubMenu(String name, int actionCode, ActionStructure parent, ActionListener itemActionListener, boolean reorganize) {
+    super(name);
+    this.parent     = parent;
+    this.actionCode = actionCode;
+    this.itemActionListener = itemActionListener;
+    if (reorganize)
+      reorganize();
+  }
+
+  /**
+   * Erzeugt ein neues Wurzel-Menue. Diesem ist keine Aktion zugeordnet und
+   * es hat keine Uebergeordneten Menues. In der Regel ist es deshalb fuer
+   * die Interpretation und Verarbeitung der ausgewaehlten Menueaktion
+   * zustaendig (ist also selbst der <code>ActionListener</code>!).
+   * @param name Anzeige-Name fuer das Untermenue.
+   */
+  public ObjectSubMenu(String name) {
+    this(name,ActionStructure.ACTION_NONE,null,null,false);
+  }
+
+  /**
+   * Erstellt die Struktur des Menues neu und ruft <code>reorganize()</code>
+   * fuer alle Untermenues auf.
+   */
+  public void reorganize() {
+    for (int i = 0; i < getItemCount(); i++)
+      if ( getItem(i) instanceof ObjectSubMenu )
+        ((ObjectSubMenu)getItem(i)).reorganize();
+  }
+
+  /**
+   * Liefert den ActionListener, der den Menuepunkten zugeordnet werden kann.
+   */
+  public ActionListener getItemActionListener() {
+    return this.itemActionListener;
+  }
+
+  /**
+   * Liefert die dem Menue uebergeordnete <code>ActionStructure</code>.
+   */
+  public ActionStructure getParentActionStructure() {
+    return parent;
+  }
+
+  /**
+   * Liefert die einzelne Aktion, die diesem Menue zugeordnet ist.
+   */
+  public int getActionCode() {
+    return actionCode;
+  }
+
+  /**
+   * Liefert die gesamte Aktionskette, die diesem Menue zugeordnet ist, in dem
+   * die einzelnen Aktionen der Kette logisch verodert werden.
+   */
+  public int getCompleteActionCode() {
+    if ( parent == null )
+      return getActionCode();
+    return getActionCode() | getParentActionStructure().getCompleteActionCode();
+  }
+
+  /**
+   * Prueft, ob zwei Actionscodes gemeinsame Komponenten beinhalten.
+   * Dies geschiet durch ein logisches UND zwischen den Aktionen, sowie
+   * einem Vergleich, ob das Ergebnis >0 ist.
+   * @param actionCode1 Aktionscode
+   * @param actionCode2 Aktionscode
+   * @return <code>true</code> gdw. die beiden Gesamt-Aktionen mindestens
+   *         eine gemeinsame Aktion haben.
+   */
+  public boolean compareActions(int actionCode1, int actionCode2) {
+    return (actionCode1 & actionCode2) > 0;
+  }
+}

Modified: trunk/src/schmitzm/swing/resource/locales/SwingResourceBundle.properties
===================================================================
--- trunk/src/schmitzm/swing/resource/locales/SwingResourceBundle.properties	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/resource/locales/SwingResourceBundle.properties	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,121 +1,150 @@
-# ---------------------------------------------------------------
-# ------ Default Translations (english) for GUI components ------
-# ------ in Package schmitzm.swing                         ------
-# ---------------------------------------------------------------
-
-Ok=Ok
-Cancel=Cancel
-Apply=Apply
-Ready=Ready
-Open=Open
-Close=Close
-Save=Save
-WaitMess=Please wait...
-FileExists=File already exists
-Details=Details...
-Warning=Warning
-Error=Error
-Information=Information
-Class=Class
-Description=Description
-InvalidInputMess=Invalid input
-Refresh=Refresh
-Reload=Reload
-Clear=Clear
-Skip=Skip
-Overwrite=Overwrite
-OverwriteAll=Overwrite all
-Replace=Replace
-CreateDuplicate=Create duplicate
-RememberChoice=Remember this choice
-Rule=Rule
-RuleToolTip=Insert your arithmetical rule here...
-Operators=Operators
-Start=Start
-Calculate=Calculate
-
-OperationTreePanel.OpDesc.and=AND
-OperationTreePanel.OpDesc.or=OR
-OperationTreePanel.OpDesc.not=NOT
-OperationTreePanel.OpDesc.abs=abs($NUMBER)
-OperationTreePanel.OpDesc.sqrt=sqrt($NUMBER)
-OperationTreePanel.OpDesc.round=round($NUMBER)
-OperationTreePanel.OpDesc.trunc=trunc($NUMBER)
-OperationTreePanel.OpDesc.isNaN=isNaN($NUMBER)
-OperationTreePanel.OpDesc.NaN=NaN
-OperationTreePanel.OpDesc.random=random number
-OperationTreePanel.OpDesc.sin=sin($NUMBER)
-OperationTreePanel.OpDesc.cos=cos($NUMBER)
-OperationTreePanel.OpDesc.tan=tan($NUMBER)
-OperationTreePanel.OpDesc.asin=arcsine($NUMBER)
-OperationTreePanel.OpDesc.acos=arccose($NUMBER)
-OperationTreePanel.OpDesc.atan=arctan($NUMBER)
-OperationTreePanel.OpDesc.exp=exp($NUMBER)
-OperationTreePanel.OpDesc.ln=ln($NUMBER)
-OperationTreePanel.OpDesc.log=log($NUMBER)
-OperationTreePanel.OpDesc.str=str($NUMBER)
-OperationTreePanel.OpDesc.val=val($TEXT)
-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.plus=+
-OperationTreePanel.OpDesc.minus=-
-OperationTreePanel.OpDesc.multiply=*
-OperationTreePanel.OpDesc.divide=/
-OperationTreePanel.OpDesc.pow=^
-OperationTreePanel.OpDesc.eq=\=
-OperationTreePanel.OpDesc.ne=<>
-OperationTreePanel.OpDesc.lt=<
-OperationTreePanel.OpDesc.le=<=
-OperationTreePanel.OpDesc.gt=>
-OperationTreePanel.OpDesc.ge=>=
-
-OperationTreePanel.OpTooltip.and=Returns TRUE only if both arguments is TRUE.
-OperationTreePanel.OpTooltip.or=Returns TRUE is any argument is TRUE.
-OperationTreePanel.OpTooltip.not=Reverses the value of the argument.
-OperationTreePanel.OpTooltip.abs=Absolute value of a number.
-OperationTreePanel.OpTooltip.sqrt=Returns the square root of a number.
-OperationTreePanel.OpTooltip.round=Rounds a number.
-OperationTreePanel.OpTooltip.trunc=Truncates the decimal places of a number.
-OperationTreePanel.OpTooltip.isNaN=Returns TRUE if value is not a number.
-OperationTreePanel.OpTooltip.NaN=The value of "NotANumber"
-OperationTreePanel.OpTooltip.random=Returns a random number between 0 and 1.
-OperationTreePanel.OpTooltip.sin=Returns the sine of a number.
-OperationTreePanel.OpTooltip.cos=Returns the cosine of a number.
-OperationTreePanel.OpTooltip.tan=Returns the tangent of a number.
-OperationTreePanel.OpTooltip.asin=Returns the arcsine of a number.
-OperationTreePanel.OpTooltip.acos=Returns the arccosine of a number.
-OperationTreePanel.OpTooltip.atan=Returns the arctangent of a number.
-OperationTreePanel.OpTooltip.exp=Calculates the exponent for basis e.
-OperationTreePanel.OpTooltip.ln=Calculates the natural logarithm of a number.
-OperationTreePanel.OpTooltip.log=Calculates the base-10 logarithm of a number.
-OperationTreePanel.OpTooltip.str=Converts a number to a text.
-OperationTreePanel.OpTooltip.val=Converts a text to a number.
-OperationTreePanel.OpTooltip.len=Calculates the length if a text string.
-OperationTreePanel.OpTooltip.toupper=Converts text to uppercase.
-OperationTreePanel.OpTooltip.tolower=Converts text to lowercase.
-OperationTreePanel.OpTooltip.ite=Specifies a logical test to be performed.
-OperationTreePanel.OpTooltip.regex=Performs regular-expressions operation on a text.
-OperationTreePanel.OpTooltip.substr=Returns only a part of a text.
-OperationTreePanel.OpTooltip.plus=Addition
-OperationTreePanel.OpTooltip.minus=-Subtraction
-OperationTreePanel.OpTooltip.multiply=Multiplication
-OperationTreePanel.OpTooltip.divide=Division
-OperationTreePanel.OpTooltip.pow=Power - e.g. $VAL ^ 9
-OperationTreePanel.OpTooltip.eq=Equals - e.g. $VAL1 = 23
-OperationTreePanel.OpTooltip.ne=Unequals - e.g. $VAL <> 45
-OperationTreePanel.OpTooltip.lt=Lesser - e.g. $VAL < $VAL2
-OperationTreePanel.OpTooltip.le=Lesser or equal
-OperationTreePanel.OpTooltip.gt=Greater
-OperationTreePanel.OpTooltip.ge=Greater or equal
-
-TranslationAskJDialog.Title=Please translate
-TranslationAskJDialog.ErrorMsg.InvalidCharacterInTranslation = Sorry, but you must not use characters { and } in any text label.
-
-
-
-
-
+##########
+#Copyright (c) 2009 Martin O. J. Schmitz.
+#
+#This file is part of the SCHMITZM library - a collection of utility 
+#classes based on Java 1.6, focussing (not only) on Java Swing 
+#and the Geotools library.
+#
+#The SCHMITZM project is hosted at:
+#http://wald.intevation.org/projects/schmitzm/
+#
+#This program is free software; you can redistribute it and/or
+#modify it under the terms of the GNU Lesser General Public License
+#as published by the Free Software Foundation; either version 3
+#of the License, or (at your option) any later version.
+#
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+#
+#You should have received a copy of the GNU Lesser General Public License (license.txt)
+#along with this program; if not, write to the Free Software
+#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#or try this link: http://www.gnu.org/licenses/lgpl.html
+#
+#Contributors:
+#    Martin O. J. Schmitz - initial API and implementation
+#    Stefan A. Krüger - additional utility classes
+##########
+# ---------------------------------------------------------------
+# ------ Default Translations (english) for GUI components ------
+# ------ in Package schmitzm.swing                         ------
+# ---------------------------------------------------------------
+
+Ok=Ok
+Cancel=Cancel
+Apply=Apply
+Ready=Ready
+Open=Open
+Close=Close
+Save=Save
+WaitMess=Please wait...
+FileExists=File already exists
+Details=Details...
+Warning=Warning
+Error=Error
+Information=Information
+Class=Class
+Description=Description
+InvalidInputMess=Invalid input
+Refresh=Refresh
+Reload=Reload
+Clear=Clear
+Skip=Skip
+Overwrite=Overwrite
+OverwriteAll=Overwrite all
+Replace=Replace
+CreateDuplicate=Create duplicate
+RememberChoice=Remember this choice
+Rule=Rule
+RuleToolTip=Insert your arithmetical rule here...
+Operators=Operators
+Start=Start
+Calculate=Calculate
+
+OperationTreePanel.OpDesc.and=AND
+OperationTreePanel.OpDesc.or=OR
+OperationTreePanel.OpDesc.not=NOT
+OperationTreePanel.OpDesc.abs=abs($NUMBER)
+OperationTreePanel.OpDesc.sqrt=sqrt($NUMBER)
+OperationTreePanel.OpDesc.round=round($NUMBER)
+OperationTreePanel.OpDesc.trunc=trunc($NUMBER)
+OperationTreePanel.OpDesc.isNaN=isNaN($NUMBER)
+OperationTreePanel.OpDesc.NaN=NaN
+OperationTreePanel.OpDesc.random=random number
+OperationTreePanel.OpDesc.sin=sin($NUMBER)
+OperationTreePanel.OpDesc.cos=cos($NUMBER)
+OperationTreePanel.OpDesc.tan=tan($NUMBER)
+OperationTreePanel.OpDesc.asin=arcsine($NUMBER)
+OperationTreePanel.OpDesc.acos=arccose($NUMBER)
+OperationTreePanel.OpDesc.atan=arctan($NUMBER)
+OperationTreePanel.OpDesc.exp=exp($NUMBER)
+OperationTreePanel.OpDesc.ln=ln($NUMBER)
+OperationTreePanel.OpDesc.log=log($NUMBER)
+OperationTreePanel.OpDesc.str=str($NUMBER)
+OperationTreePanel.OpDesc.val=val($TEXT)
+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.plus=+
+OperationTreePanel.OpDesc.minus=-
+OperationTreePanel.OpDesc.multiply=*
+OperationTreePanel.OpDesc.divide=/
+OperationTreePanel.OpDesc.pow=^
+OperationTreePanel.OpDesc.eq=\=
+OperationTreePanel.OpDesc.ne=<>
+OperationTreePanel.OpDesc.lt=<
+OperationTreePanel.OpDesc.le=<=
+OperationTreePanel.OpDesc.gt=>
+OperationTreePanel.OpDesc.ge=>=
+
+OperationTreePanel.OpTooltip.and=Returns TRUE only if both arguments is TRUE.
+OperationTreePanel.OpTooltip.or=Returns TRUE is any argument is TRUE.
+OperationTreePanel.OpTooltip.not=Reverses the value of the argument.
+OperationTreePanel.OpTooltip.abs=Absolute value of a number.
+OperationTreePanel.OpTooltip.sqrt=Returns the square root of a number.
+OperationTreePanel.OpTooltip.round=Rounds a number.
+OperationTreePanel.OpTooltip.trunc=Truncates the decimal places of a number.
+OperationTreePanel.OpTooltip.isNaN=Returns TRUE if value is not a number.
+OperationTreePanel.OpTooltip.NaN=The value of "NotANumber"
+OperationTreePanel.OpTooltip.random=Returns a random number between 0 and 1.
+OperationTreePanel.OpTooltip.sin=Returns the sine of a number.
+OperationTreePanel.OpTooltip.cos=Returns the cosine of a number.
+OperationTreePanel.OpTooltip.tan=Returns the tangent of a number.
+OperationTreePanel.OpTooltip.asin=Returns the arcsine of a number.
+OperationTreePanel.OpTooltip.acos=Returns the arccosine of a number.
+OperationTreePanel.OpTooltip.atan=Returns the arctangent of a number.
+OperationTreePanel.OpTooltip.exp=Calculates the exponent for basis e.
+OperationTreePanel.OpTooltip.ln=Calculates the natural logarithm of a number.
+OperationTreePanel.OpTooltip.log=Calculates the base-10 logarithm of a number.
+OperationTreePanel.OpTooltip.str=Converts a number to a text.
+OperationTreePanel.OpTooltip.val=Converts a text to a number.
+OperationTreePanel.OpTooltip.len=Calculates the length if a text string.
+OperationTreePanel.OpTooltip.toupper=Converts text to uppercase.
+OperationTreePanel.OpTooltip.tolower=Converts text to lowercase.
+OperationTreePanel.OpTooltip.ite=Specifies a logical test to be performed.
+OperationTreePanel.OpTooltip.regex=Performs regular-expressions operation on a text.
+OperationTreePanel.OpTooltip.substr=Returns only a part of a text.
+OperationTreePanel.OpTooltip.plus=Addition
+OperationTreePanel.OpTooltip.minus=-Subtraction
+OperationTreePanel.OpTooltip.multiply=Multiplication
+OperationTreePanel.OpTooltip.divide=Division
+OperationTreePanel.OpTooltip.pow=Power - e.g. $VAL ^ 9
+OperationTreePanel.OpTooltip.eq=Equals - e.g. $VAL1 = 23
+OperationTreePanel.OpTooltip.ne=Unequals - e.g. $VAL <> 45
+OperationTreePanel.OpTooltip.lt=Lesser - e.g. $VAL < $VAL2
+OperationTreePanel.OpTooltip.le=Lesser or equal
+OperationTreePanel.OpTooltip.gt=Greater
+OperationTreePanel.OpTooltip.ge=Greater or equal
+
+TranslationAskJDialog.Title=Please translate
+TranslationAskJDialog.ErrorMsg.InvalidCharacterInTranslation = Sorry, but you must not use characters { and } in any text label.
+
+
+
+
+

Modified: trunk/src/schmitzm/swing/resource/locales/SwingResourceBundle_de.properties
===================================================================
--- trunk/src/schmitzm/swing/resource/locales/SwingResourceBundle_de.properties	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/resource/locales/SwingResourceBundle_de.properties	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,101 +1,130 @@
-# ----------------------------------------------------
-# ------ German Translations for GUI components ------
-# ------ in Package schmitzm.swing              ------
-# ----------------------------------------------------
-
-Cancel=Abbrechen
-Apply=Übernehmen
-Ready=Fertig
-Open=Öffnen
-Close=Schliessen
-Save=Speichern
-WaitMess=Bitte warten...
-FileExists=Datei existiert bereits
-Warning=Warnung
-Error=Fehler
-Class=Klasse
-Description=Beschreibung
-InvalidInputMess=Unzulässige Eingabe
-Refresh=Aktualisieren
-Reload=Neu laden
-Clear=Löschen
-Skip=Übergehen
-Overwrite=Überschreiben
-OverwriteAll=Alle überschreiben
-Replace=Ersetzen
-CreateDuplicate=Duplikat erzeugen
-RememberChoice=Immer diese Auswahl treffen
-Rule=Formel
-RuleToolTip=Hier eine arithmetische Formel eingeben...
-Operators=Operatoren
-Start=Start
-Calculate=Rechnen
-
-OperationTreePanel.OpDesc.and=UND
-OperationTreePanel.OpDesc.or=ODER
-OperationTreePanel.OpDesc.not=NICHT
-OperationTreePanel.OpDesc.abs=abs($NUMBER)
-OperationTreePanel.OpDesc.random=Zufallszahl
-OperationTreePanel.OpDesc.asin=arcsin($NUMBER)
-OperationTreePanel.OpDesc.acos=arccos($NUMBER)
-
-OperationTreePanel.OpDesc.str=str($NUMBER)
-OperationTreePanel.OpDesc.val=val($TEXT)
-OperationTreePanel.OpDesc.len=len($TEXT)
-OperationTreePanel.OpDesc.toupper=toupper($TEXT)
-OperationTreePanel.OpDesc.tolower=tolower($TEXT)
-OperationTreePanel.OpDesc.ite=WENN .. DANN .. SONST ..
-
-OperationTreePanel.OpDesc.plus=+
-OperationTreePanel.OpDesc.minus=-
-OperationTreePanel.OpDesc.multiply=*
-OperationTreePanel.OpDesc.divide=/
-OperationTreePanel.OpDesc.pow=^
-OperationTreePanel.OpDesc.eq=\=
-OperationTreePanel.OpDesc.ne=<>
-OperationTreePanel.OpDesc.lt=<
-OperationTreePanel.OpDesc.le=<=
-OperationTreePanel.OpDesc.gt=>
-OperationTreePanel.OpDesc.ge=>=
-
-OperationTreePanel.OpTooltip.and=Liefert WAHR, wenn beide Argumente WAHR sind. 
-OperationTreePanel.OpTooltip.or=Liefert WAHR, sobald ein Argument WAHR ist.
-OperationTreePanel.OpTooltip.not=Invertiet WAHR zu FALSCH und FLASCH zu WAHR.
-OperationTreePanel.OpTooltip.abs=Absoluter Wert einer Zahl.
-OperationTreePanel.OpTooltip.sqrt=Liefert die Wurzel einer Zahl.
-OperationTreePanel.OpTooltip.round=Rundet eine Dezimal-Zahl zu einer Ganzzahl.
-OperationTreePanel.OpTooltip.trunc=Schneidet Nachkommastellen ab.
-OperationTreePanel.OpTooltip.isNaN=Liefert WAHR, wenn die Zahl "keine Zahl" ist (z.B. bei Division durch Null).
-OperationTreePanel.OpTooltip.NaN=Der Wert "keine Zahl".
-OperationTreePanel.OpTooltip.random=Liefert eine Zufallszahl zwischen 0 und 1.
-OperationTreePanel.OpTooltip.sin=Liefert den Sinus-Wert zu einer Zahl.
-OperationTreePanel.OpTooltip.cos=Liefert den Cosinus-Wert zu einer Zahl.
-OperationTreePanel.OpTooltip.tan=Liefert den Tangenz-Wert zu einer Zahl.
-OperationTreePanel.OpTooltip.asin=Liefert den Arcus-Sinus-Wert zu einer Zahl.
-OperationTreePanel.OpTooltip.acos=Liefert den Arcus-Cosinus-Wert zu einer Zahl.
-OperationTreePanel.OpTooltip.atan=Liefert den Arcus-Tangens-Wert zu einer Zahl.
-OperationTreePanel.OpTooltip.exp=Berechnet die Exponenzialfunktion (e^x).
-OperationTreePanel.OpTooltip.ln=Berechnet die Logarithmus-Funktion zur Basis e.
-OperationTreePanel.OpTooltip.log=Berechnet die Logarithmus-Funktion zur Basis 10.
-OperationTreePanel.OpTooltip.str=Konvertiert eine Zahl in einen Text.
-OperationTreePanel.OpTooltip.val=Konvertiert einen Text in eine Zahl.
-OperationTreePanel.OpTooltip.len=Berechnet die Länge eines Texts.
-OperationTreePanel.OpTooltip.toupper=Konvertiert Text in Großbuchstaben.
-OperationTreePanel.OpTooltip.tolower=Konvertiert Text in Kleinbuchstaben.
-OperationTreePanel.OpTooltip.ite=Spezifiziert einen logischen Test.
-OperationTreePanel.OpTooltip.regex=Wertet einen regulären Ausdruck auf einem Text aus.
-OperationTreePanel.OpTooltip.substr=Liefert einen Teil-String.
-OperationTreePanel.OpTooltip.plus=Addition
-OperationTreePanel.OpTooltip.minus=Subtraktion
-OperationTreePanel.OpTooltip.multiply=Multiplikation
-OperationTreePanel.OpTooltip.divide=Division
-OperationTreePanel.OpTooltip.pow=Potenzfunktion
-OperationTreePanel.OpTooltip.eq=Gleich
-OperationTreePanel.OpTooltip.ne=Ungleich
-OperationTreePanel.OpTooltip.lt=Kleiner als
-OperationTreePanel.OpTooltip.le=Kleiner oder gleich
-OperationTreePanel.OpTooltip.gt=Größer als 
-OperationTreePanel.OpTooltip.ge=Größer oder gleich
-
-TranslationAskJDialog.Title=Bitte übersetzen
-TranslationAskJDialog.ErrorMsg.InvalidCharacterInTranslation = Die Zeichen { und } dürfen Sie leider nicht benutzen.
\ No newline at end of file
+##########
+#Copyright (c) 2009 Martin O. J. Schmitz.
+#
+#This file is part of the SCHMITZM library - a collection of utility 
+#classes based on Java 1.6, focussing (not only) on Java Swing 
+#and the Geotools library.
+#
+#The SCHMITZM project is hosted at:
+#http://wald.intevation.org/projects/schmitzm/
+#
+#This program is free software; you can redistribute it and/or
+#modify it under the terms of the GNU Lesser General Public License
+#as published by the Free Software Foundation; either version 3
+#of the License, or (at your option) any later version.
+#
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+#
+#You should have received a copy of the GNU Lesser General Public License (license.txt)
+#along with this program; if not, write to the Free Software
+#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#or try this link: http://www.gnu.org/licenses/lgpl.html
+#
+#Contributors:
+#    Martin O. J. Schmitz - initial API and implementation
+#    Stefan A. Krüger - additional utility classes
+##########
+# ----------------------------------------------------
+# ------ German Translations for GUI components ------
+# ------ in Package schmitzm.swing              ------
+# ----------------------------------------------------
+
+Cancel=Abbrechen
+Apply=Übernehmen
+Ready=Fertig
+Open=Öffnen
+Close=Schliessen
+Save=Speichern
+WaitMess=Bitte warten...
+FileExists=Datei existiert bereits
+Warning=Warnung
+Error=Fehler
+Class=Klasse
+Description=Beschreibung
+InvalidInputMess=Unzulässige Eingabe
+Refresh=Aktualisieren
+Reload=Neu laden
+Clear=Löschen
+Skip=Übergehen
+Overwrite=Überschreiben
+OverwriteAll=Alle überschreiben
+Replace=Ersetzen
+CreateDuplicate=Duplikat erzeugen
+RememberChoice=Immer diese Auswahl treffen
+Rule=Formel
+RuleToolTip=Hier eine arithmetische Formel eingeben...
+Operators=Operatoren
+Start=Start
+Calculate=Rechnen
+
+OperationTreePanel.OpDesc.and=UND
+OperationTreePanel.OpDesc.or=ODER
+OperationTreePanel.OpDesc.not=NICHT
+OperationTreePanel.OpDesc.abs=abs($NUMBER)
+OperationTreePanel.OpDesc.random=Zufallszahl
+OperationTreePanel.OpDesc.asin=arcsin($NUMBER)
+OperationTreePanel.OpDesc.acos=arccos($NUMBER)
+
+OperationTreePanel.OpDesc.str=str($NUMBER)
+OperationTreePanel.OpDesc.val=val($TEXT)
+OperationTreePanel.OpDesc.len=len($TEXT)
+OperationTreePanel.OpDesc.toupper=toupper($TEXT)
+OperationTreePanel.OpDesc.tolower=tolower($TEXT)
+OperationTreePanel.OpDesc.ite=WENN .. DANN .. SONST ..
+
+OperationTreePanel.OpDesc.plus=+
+OperationTreePanel.OpDesc.minus=-
+OperationTreePanel.OpDesc.multiply=*
+OperationTreePanel.OpDesc.divide=/
+OperationTreePanel.OpDesc.pow=^
+OperationTreePanel.OpDesc.eq=\=
+OperationTreePanel.OpDesc.ne=<>
+OperationTreePanel.OpDesc.lt=<
+OperationTreePanel.OpDesc.le=<=
+OperationTreePanel.OpDesc.gt=>
+OperationTreePanel.OpDesc.ge=>=
+
+OperationTreePanel.OpTooltip.and=Liefert WAHR, wenn beide Argumente WAHR sind. 
+OperationTreePanel.OpTooltip.or=Liefert WAHR, sobald ein Argument WAHR ist.
+OperationTreePanel.OpTooltip.not=Invertiet WAHR zu FALSCH und FLASCH zu WAHR.
+OperationTreePanel.OpTooltip.abs=Absoluter Wert einer Zahl.
+OperationTreePanel.OpTooltip.sqrt=Liefert die Wurzel einer Zahl.
+OperationTreePanel.OpTooltip.round=Rundet eine Dezimal-Zahl zu einer Ganzzahl.
+OperationTreePanel.OpTooltip.trunc=Schneidet Nachkommastellen ab.
+OperationTreePanel.OpTooltip.isNaN=Liefert WAHR, wenn die Zahl "keine Zahl" ist (z.B. bei Division durch Null).
+OperationTreePanel.OpTooltip.NaN=Der Wert "keine Zahl".
+OperationTreePanel.OpTooltip.random=Liefert eine Zufallszahl zwischen 0 und 1.
+OperationTreePanel.OpTooltip.sin=Liefert den Sinus-Wert zu einer Zahl.
+OperationTreePanel.OpTooltip.cos=Liefert den Cosinus-Wert zu einer Zahl.
+OperationTreePanel.OpTooltip.tan=Liefert den Tangenz-Wert zu einer Zahl.
+OperationTreePanel.OpTooltip.asin=Liefert den Arcus-Sinus-Wert zu einer Zahl.
+OperationTreePanel.OpTooltip.acos=Liefert den Arcus-Cosinus-Wert zu einer Zahl.
+OperationTreePanel.OpTooltip.atan=Liefert den Arcus-Tangens-Wert zu einer Zahl.
+OperationTreePanel.OpTooltip.exp=Berechnet die Exponenzialfunktion (e^x).
+OperationTreePanel.OpTooltip.ln=Berechnet die Logarithmus-Funktion zur Basis e.
+OperationTreePanel.OpTooltip.log=Berechnet die Logarithmus-Funktion zur Basis 10.
+OperationTreePanel.OpTooltip.str=Konvertiert eine Zahl in einen Text.
+OperationTreePanel.OpTooltip.val=Konvertiert einen Text in eine Zahl.
+OperationTreePanel.OpTooltip.len=Berechnet die Länge eines Texts.
+OperationTreePanel.OpTooltip.toupper=Konvertiert Text in Großbuchstaben.
+OperationTreePanel.OpTooltip.tolower=Konvertiert Text in Kleinbuchstaben.
+OperationTreePanel.OpTooltip.ite=Spezifiziert einen logischen Test.
+OperationTreePanel.OpTooltip.regex=Wertet einen regulären Ausdruck auf einem Text aus.
+OperationTreePanel.OpTooltip.substr=Liefert einen Teil-String.
+OperationTreePanel.OpTooltip.plus=Addition
+OperationTreePanel.OpTooltip.minus=Subtraktion
+OperationTreePanel.OpTooltip.multiply=Multiplikation
+OperationTreePanel.OpTooltip.divide=Division
+OperationTreePanel.OpTooltip.pow=Potenzfunktion
+OperationTreePanel.OpTooltip.eq=Gleich
+OperationTreePanel.OpTooltip.ne=Ungleich
+OperationTreePanel.OpTooltip.lt=Kleiner als
+OperationTreePanel.OpTooltip.le=Kleiner oder gleich
+OperationTreePanel.OpTooltip.gt=Größer als 
+OperationTreePanel.OpTooltip.ge=Größer oder gleich
+
+TranslationAskJDialog.Title=Bitte übersetzen
+TranslationAskJDialog.ErrorMsg.InvalidCharacterInTranslation = Die Zeichen { und } dürfen Sie leider nicht benutzen.

Modified: trunk/src/schmitzm/swing/resource/locales/SwingResourceBundle_fr.properties
===================================================================
--- trunk/src/schmitzm/swing/resource/locales/SwingResourceBundle_fr.properties	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/resource/locales/SwingResourceBundle_fr.properties	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,3 +1,32 @@
+##########
+#Copyright (c) 2009 Martin O. J. Schmitz.
+#
+#This file is part of the SCHMITZM library - a collection of utility 
+#classes based on Java 1.6, focussing (not only) on Java Swing 
+#and the Geotools library.
+#
+#The SCHMITZM project is hosted at:
+#http://wald.intevation.org/projects/schmitzm/
+#
+#This program is free software; you can redistribute it and/or
+#modify it under the terms of the GNU Lesser General Public License
+#as published by the Free Software Foundation; either version 3
+#of the License, or (at your option) any later version.
+#
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+#
+#You should have received a copy of the GNU Lesser General Public License (license.txt)
+#along with this program; if not, write to the Free Software
+#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#or try this link: http://www.gnu.org/licenses/lgpl.html
+#
+#Contributors:
+#    Martin O. J. Schmitz - initial API and implementation
+#    Stefan A. Krüger - additional utility classes
+##########
 # ----------------------------------------------------
 # ------ German Translations for GUI components ------
 # ------ in Package schmitzm.swing              ------
@@ -90,4 +119,4 @@
 OperationTreePanel.OpTooltip.ge=plus grand(e)ou égal à  
 
 TranslationAskJDialog.Title=Traduisez S.V.P.
-TranslationAskJDialog.ErrorMsg.InvalidCharacterInTranslation = Vous ne pouvez malheureusement pas utiliser ces lettres { et }
\ No newline at end of file
+TranslationAskJDialog.ErrorMsg.InvalidCharacterInTranslation = Vous ne pouvez malheureusement pas utiliser ces lettres { et }

Modified: trunk/src/schmitzm/swing/table/AbstractMutableTableModel.java
===================================================================
--- trunk/src/schmitzm/swing/table/AbstractMutableTableModel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/table/AbstractMutableTableModel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,33 +1,52 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.swing.table;
-
-import javax.swing.JTable;
-import javax.swing.table.TableModel;
-
-/**
- * Diese Klasse erweitert das {@link AbstractTableModel} um die Methoden
- * des {@link MutableTableModel}.
- * @see MutableTable
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public abstract class AbstractMutableTableModel extends AbstractTableModel implements MutableTableModel {
-  /**
-   * Macht nichts. Wird von {@link MutableTable#setModel(TableModel)}
-   * aufgerufen. Bietet die Moeglichkeit, Tabellenmodell-spezifische
-   * Eigenschaften an der darstellenden Tabelle automatisch durch
-   * das Tabellenmodell zu setzen.
-   * @param table Tabelle, in der das {@link TableModel} dargestellt wird
-   */
-  public void initTable(JTable table) {
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing.table;
+
+import javax.swing.JTable;
+import javax.swing.table.TableModel;
+
+/**
+ * Diese Klasse erweitert das {@link AbstractTableModel} um die Methoden
+ * des {@link MutableTableModel}.
+ * @see MutableTable
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public abstract class AbstractMutableTableModel extends AbstractTableModel implements MutableTableModel {
+  /**
+   * Macht nichts. Wird von {@link MutableTable#setModel(TableModel)}
+   * aufgerufen. Bietet die Moeglichkeit, Tabellenmodell-spezifische
+   * Eigenschaften an der darstellenden Tabelle automatisch durch
+   * das Tabellenmodell zu setzen.
+   * @param table Tabelle, in der das {@link TableModel} dargestellt wird
+   */
+  public void initTable(JTable table) {
+  }
+}

Modified: trunk/src/schmitzm/swing/table/AbstractTableModel.java
===================================================================
--- trunk/src/schmitzm/swing/table/AbstractTableModel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/table/AbstractTableModel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,58 +1,77 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.swing.table;
-
-/**
- * Erweitert das Java {@link javax.swing.table.AbstractTableModel} in dem die
- * Methoden {@code #getColumnName(int)} und {@link #getColumnCount()} bereits
- * implementiert sind. Diese werden durch die neue abstrakte Methode
- * {@link #createColumnNames()} bestimmt.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- *
- */
-public abstract class AbstractTableModel extends javax.swing.table.AbstractTableModel {
-
-  /** Beinhaltet die Spaltennamen.
-   *  @see #createColumnNames() */
-  protected String[] colNames = createColumnNames();
-
-  /**
-   * Liefert die Anzahl an Spalten.
-   * @param col Spaltenindex (beginnend bei 0)
-   */
-  public int getColumnCount() {
-    return colNames.length;
-  }
-
-  /**
-   * Liefert den Namen einer Spalte.
-   * @param col Spaltenindex (beginnend bei 0)
-   */
-  @Override
-  public String getColumnName(int col) {
-    return colNames[col];
-  }
-
-  /**
-   * Liefert die Spaltennamen der Tabelle. Diese Methode liefert direkten
-   * Zugriff auf den Array der Spaltennamen, so dass dessen Inhalt veraendert
-   * werden kann (z.B. fuer Internationalisierung).
-   */
-  public String[] getColumnNames()  {
-    return colNames;
-  }
-
-  /**
-   * Erzeugt die Spaltennamen der Tabelle.
-   */
-  public abstract String[] createColumnNames();
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing.table;
+
+/**
+ * Erweitert das Java {@link javax.swing.table.AbstractTableModel} in dem die
+ * Methoden {@code #getColumnName(int)} und {@link #getColumnCount()} bereits
+ * implementiert sind. Diese werden durch die neue abstrakte Methode
+ * {@link #createColumnNames()} bestimmt.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ *
+ */
+public abstract class AbstractTableModel extends javax.swing.table.AbstractTableModel {
+
+  /** Beinhaltet die Spaltennamen.
+   *  @see #createColumnNames() */
+  protected String[] colNames = createColumnNames();
+
+  /**
+   * Liefert die Anzahl an Spalten.
+   * @param col Spaltenindex (beginnend bei 0)
+   */
+  public int getColumnCount() {
+    return colNames.length;
+  }
+
+  /**
+   * Liefert den Namen einer Spalte.
+   * @param col Spaltenindex (beginnend bei 0)
+   */
+  @Override
+  public String getColumnName(int col) {
+    return colNames[col];
+  }
+
+  /**
+   * Liefert die Spaltennamen der Tabelle. Diese Methode liefert direkten
+   * Zugriff auf den Array der Spaltennamen, so dass dessen Inhalt veraendert
+   * werden kann (z.B. fuer Internationalisierung).
+   */
+  public String[] getColumnNames()  {
+    return colNames;
+  }
+
+  /**
+   * Erzeugt die Spaltennamen der Tabelle.
+   */
+  public abstract String[] createColumnNames();
+
+}

Modified: trunk/src/schmitzm/swing/table/ColorEditor.java
===================================================================
--- trunk/src/schmitzm/swing/table/ColorEditor.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/table/ColorEditor.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,16 +1,34 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing.table;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing.table;
-
 import java.awt.Color;
 import java.awt.Component;
 import java.awt.event.ActionEvent;
@@ -22,83 +40,83 @@
 import javax.swing.JDialog;
 import javax.swing.JTable;
 import javax.swing.table.TableCellEditor;
-
-/**
- * Diese Klasse stellt einen Editor fuer eine Tabellen-Zelle dar, welche
- * ein {@link Color}-Objekt beinhaltet. Dieser wird durch einen Button
- * repraesentiert. Wird dieser aktiviert erscheint ein {@link JColorChooser}
- * ueber den eine neue Farbe ausgewaehlt werden kann.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of  Bonn/Germany)
- * @version 1.0
- */
-public class ColorEditor extends AbstractCellEditor implements TableCellEditor, ActionListener {
-  private Color         currentColor;
-  private JButton       button;
-  private JColorChooser colorChooser;
-  private JDialog       dialog;
-  protected static final String EDIT = "edit";
-
-  /**
-   * Erzeugt einen neuen Editor.
-   */
-  public ColorEditor() {
-    //Set up the editor (from the table's point of view),
-    //which is a button.
-    //This button brings up the color chooser dialog,
-    //which is the editor from the user's point of view.
-    button = new JButton();
-    button.setActionCommand(EDIT);
-    button.addActionListener(this);
-    button.setBorderPainted(false);
-
-    //Set up the dialog that the button brings up.
-    colorChooser = new JColorChooser();
-    dialog = JColorChooser.createDialog(button,
-                                        "Pick a Color",
-                                        true, //modal
-                                        colorChooser,
-                                        this, //OK button handler
-                                        null); //no CANCEL button handler
-  }
-
-  /**
-   * Verarbeitet den "Klick" auf die Tabellenzelle (Button). Ruft einen
-   * {@link JColorChooser} auf, ueber den eine Farbe ausgewaehlt werden
-   * kann.
-   */
-  public void actionPerformed(ActionEvent e) {
-    if (EDIT.equals(e.getActionCommand())) {
-      //The user has clicked the cell, so
-      //bring up the dialog.
-      button.setBackground(currentColor);
-      colorChooser.setColor(currentColor);
-      dialog.setVisible(true);
-      //Make the renderer reappear.
-      fireEditingStopped();
-    } else {
-      //User pressed dialog's "OK" button.
-      currentColor = colorChooser.getColor();
-    }
-  }
-
-  /**
-   * Liefert die aktuell ausgewaehlte Farbe.
-   * @return <code>Color</code>-Instanz
-   */
-  public Object getCellEditorValue() {
-    return currentColor;
-  }
-
-  /**
-   * Liefert die Komponente, die den Editor repraesentiert.
-   * Hierbei handelt es sich um einen {@link JButton}.
-   */
-  public Component getTableCellEditorComponent(JTable table,
-                                               Object value,
-                                               boolean isSelected,
-                                               int row,
-                                               int column) {
-    currentColor = (Color) value;
-    return button;
-  }
-}
+
+/**
+ * Diese Klasse stellt einen Editor fuer eine Tabellen-Zelle dar, welche
+ * ein {@link Color}-Objekt beinhaltet. Dieser wird durch einen Button
+ * repraesentiert. Wird dieser aktiviert erscheint ein {@link JColorChooser}
+ * ueber den eine neue Farbe ausgewaehlt werden kann.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of  Bonn/Germany)
+ * @version 1.0
+ */
+public class ColorEditor extends AbstractCellEditor implements TableCellEditor, ActionListener {
+  private Color         currentColor;
+  private JButton       button;
+  private JColorChooser colorChooser;
+  private JDialog       dialog;
+  protected static final String EDIT = "edit";
+
+  /**
+   * Erzeugt einen neuen Editor.
+   */
+  public ColorEditor() {
+    //Set up the editor (from the table's point of view),
+    //which is a button.
+    //This button brings up the color chooser dialog,
+    //which is the editor from the user's point of view.
+    button = new JButton();
+    button.setActionCommand(EDIT);
+    button.addActionListener(this);
+    button.setBorderPainted(false);
+
+    //Set up the dialog that the button brings up.
+    colorChooser = new JColorChooser();
+    dialog = JColorChooser.createDialog(button,
+                                        "Pick a Color",
+                                        true, //modal
+                                        colorChooser,
+                                        this, //OK button handler
+                                        null); //no CANCEL button handler
+  }
+
+  /**
+   * Verarbeitet den "Klick" auf die Tabellenzelle (Button). Ruft einen
+   * {@link JColorChooser} auf, ueber den eine Farbe ausgewaehlt werden
+   * kann.
+   */
+  public void actionPerformed(ActionEvent e) {
+    if (EDIT.equals(e.getActionCommand())) {
+      //The user has clicked the cell, so
+      //bring up the dialog.
+      button.setBackground(currentColor);
+      colorChooser.setColor(currentColor);
+      dialog.setVisible(true);
+      //Make the renderer reappear.
+      fireEditingStopped();
+    } else {
+      //User pressed dialog's "OK" button.
+      currentColor = colorChooser.getColor();
+    }
+  }
+
+  /**
+   * Liefert die aktuell ausgewaehlte Farbe.
+   * @return <code>Color</code>-Instanz
+   */
+  public Object getCellEditorValue() {
+    return currentColor;
+  }
+
+  /**
+   * Liefert die Komponente, die den Editor repraesentiert.
+   * Hierbei handelt es sich um einen {@link JButton}.
+   */
+  public Component getTableCellEditorComponent(JTable table,
+                                               Object value,
+                                               boolean isSelected,
+                                               int row,
+                                               int column) {
+    currentColor = (Color) value;
+    return button;
+  }
+}

Modified: trunk/src/schmitzm/swing/table/ColorRenderer.java
===================================================================
--- trunk/src/schmitzm/swing/table/ColorRenderer.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/table/ColorRenderer.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,16 +1,34 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing.table;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing.table;
-
 import java.awt.Color;
 import java.awt.Component;
 
@@ -19,92 +37,92 @@
 import javax.swing.JTable;
 import javax.swing.border.Border;
 import javax.swing.table.TableCellRenderer;
-
-/**
- * Diese Klasse stellt einen Renderer fuer Tabellenzellen dar, in denen
- * eine Farbe (also eine <code>Color</code>-Instanz) dargestellt werden soll.<br>
- * Die Farbe wird durch ein {@link JLabel} in entsprechender Hintergrundfarbe
- * dargestellt.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class ColorRenderer extends JLabel implements TableCellRenderer {
-    private   Border  unselectedBorder = null;
-    private   Border  selectedBorder   = null;
-    /** Speichert, ob die Zelle einen inneren Rand erhaelt */
-    protected boolean isBordered = true;
-
-  /**
-   * Erzeugt einen neuen Zellen-Renderer.
-   * @param isBordered gibt an ob die Zelle komplett ausgefuellt wird, oder
-   *                   ein innerer Rand erzeugt wird
-   */
-  public ColorRenderer(boolean isBordered) {
-    this.isBordered = isBordered;
-    setOpaque(true);
-  }
-
-  /**
-   * Liefert einen {@link JLabel}, das die in der Tabellenzelle enthaltene
-   * Farbe darstellt.
-   * @param table      Tabelle in der die Zelle liegt
-   * @param color      Farbe, die in der Zelle darzustellen ist (<b>muss eine
-   *                   Instanz von <code>Color</code> sein!!</b>)
-   * @param isSelected gibt an ob die Zelle aktuell selektiert ist
-   * @param hasFocus   gibt an ob die Zelle aktuell den Fokus besitzt
-   * @param row        Tabellenzeile der Zelle
-   * @param column     Tabellenspalte der Zelle
-   * @return ein farbiges {@link JLabel}
-   */
-  public Component getTableCellRendererComponent(
-                               JTable table,
-                               Object color,
-                               boolean isSelected,
-                               boolean hasFocus,
-                               int row,
-                               int column) {
-    // Randarten erzeugen, falls dies noch nicht geschehen ist
-    if (selectedBorder == null) {
-      selectedBorder = BorderFactory.createMatteBorder(
-          2, 5, 2, 5,
-          table.getSelectionBackground()
-      );
-    }
-    if (unselectedBorder == null) {
-      unselectedBorder = BorderFactory.createMatteBorder(
-          2, 5, 2, 5,
-          table.getBackground()
-      );
-    }
-    // Rand setzen
-    if (isBordered) {
-      if (isSelected)
-        setBorder(selectedBorder);
-      else
-        setBorder(unselectedBorder);
-    }
-    // Label erzeugen/initialisieren
-    return createColorLabel((Color)color,this);
-  }
-
-  /**
-   * Liefert einen {@link JLabel}, das eine Farbe darstellt. Ist der uebergebene
-   * <code>label</code>-Parameter <code>null</code> wird eine neue
-   * {@link JLabel}-Instanz erzeugt.
-   * @param color Farbe, die durch das Label dargestellt wird
-   * @param label Label, das entsprechend der Farbe umformatiert (kann
-   *              <code>null</code> sein)
-   */
-  public static JLabel createColorLabel(Color color, JLabel label) {
-    if (label == null)
-      label = new JLabel();
-
-    label.setOpaque(true);
-    label.setBackground(color);
-    if ( color != null )
-      label.setToolTipText("RGB value: " + color.getRed() + ", "
-                           + color.getGreen() + ", "
-                           + color.getBlue());
-    return label;
-  }
-}
+
+/**
+ * Diese Klasse stellt einen Renderer fuer Tabellenzellen dar, in denen
+ * eine Farbe (also eine <code>Color</code>-Instanz) dargestellt werden soll.<br>
+ * Die Farbe wird durch ein {@link JLabel} in entsprechender Hintergrundfarbe
+ * dargestellt.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class ColorRenderer extends JLabel implements TableCellRenderer {
+    private   Border  unselectedBorder = null;
+    private   Border  selectedBorder   = null;
+    /** Speichert, ob die Zelle einen inneren Rand erhaelt */
+    protected boolean isBordered = true;
+
+  /**
+   * Erzeugt einen neuen Zellen-Renderer.
+   * @param isBordered gibt an ob die Zelle komplett ausgefuellt wird, oder
+   *                   ein innerer Rand erzeugt wird
+   */
+  public ColorRenderer(boolean isBordered) {
+    this.isBordered = isBordered;
+    setOpaque(true);
+  }
+
+  /**
+   * Liefert einen {@link JLabel}, das die in der Tabellenzelle enthaltene
+   * Farbe darstellt.
+   * @param table      Tabelle in der die Zelle liegt
+   * @param color      Farbe, die in der Zelle darzustellen ist (<b>muss eine
+   *                   Instanz von <code>Color</code> sein!!</b>)
+   * @param isSelected gibt an ob die Zelle aktuell selektiert ist
+   * @param hasFocus   gibt an ob die Zelle aktuell den Fokus besitzt
+   * @param row        Tabellenzeile der Zelle
+   * @param column     Tabellenspalte der Zelle
+   * @return ein farbiges {@link JLabel}
+   */
+  public Component getTableCellRendererComponent(
+                               JTable table,
+                               Object color,
+                               boolean isSelected,
+                               boolean hasFocus,
+                               int row,
+                               int column) {
+    // Randarten erzeugen, falls dies noch nicht geschehen ist
+    if (selectedBorder == null) {
+      selectedBorder = BorderFactory.createMatteBorder(
+          2, 5, 2, 5,
+          table.getSelectionBackground()
+      );
+    }
+    if (unselectedBorder == null) {
+      unselectedBorder = BorderFactory.createMatteBorder(
+          2, 5, 2, 5,
+          table.getBackground()
+      );
+    }
+    // Rand setzen
+    if (isBordered) {
+      if (isSelected)
+        setBorder(selectedBorder);
+      else
+        setBorder(unselectedBorder);
+    }
+    // Label erzeugen/initialisieren
+    return createColorLabel((Color)color,this);
+  }
+
+  /**
+   * Liefert einen {@link JLabel}, das eine Farbe darstellt. Ist der uebergebene
+   * <code>label</code>-Parameter <code>null</code> wird eine neue
+   * {@link JLabel}-Instanz erzeugt.
+   * @param color Farbe, die durch das Label dargestellt wird
+   * @param label Label, das entsprechend der Farbe umformatiert (kann
+   *              <code>null</code> sein)
+   */
+  public static JLabel createColorLabel(Color color, JLabel label) {
+    if (label == null)
+      label = new JLabel();
+
+    label.setOpaque(true);
+    label.setBackground(color);
+    if ( color != null )
+      label.setToolTipText("RGB value: " + color.getRed() + ", "
+                           + color.getGreen() + ", "
+                           + color.getBlue());
+    return label;
+  }
+}

Modified: trunk/src/schmitzm/swing/table/ColorsRenderer.java
===================================================================
--- trunk/src/schmitzm/swing/table/ColorsRenderer.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/table/ColorsRenderer.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,16 +1,34 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing.table;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing.table;
-
 import java.awt.Color;
 import java.awt.Component;
 import java.awt.GridBagConstraints;
@@ -22,61 +40,61 @@
 import javax.swing.JLabel;
 import javax.swing.JTable;
 import javax.swing.border.Border;
-
-/**
- * Diese Klasse stellt einen Renderer fuer Tabellenzellen dar, in denen
- * mehrere Farben (also ein <code>Color[]</code>) dargestellt werden sollen.<br>
- * Jede Farbe wird durch ein {@link JLabel} in entsprechender Hintergrundfarbe
- * dargestellt. Die Label werden horizontal angeordnet.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class ColorsRenderer extends ColorRenderer {
-  // Rand um Farb-Label
-  private Border labelBorder = BorderFactory.createLineBorder(Color.BLACK);
-
-  /**
-   * Erzeugt einen neuen Zellen-Renderer.
-   * @param isBordered gibt an ob die Zelle komplett ausgefuellt wird, oder
-   *                   ein Rand erzeugt wird
-   */
-  public ColorsRenderer(boolean isBordered) {
-    super(isBordered);
-    this.setLayout( new GridBagLayout() );
-  }
-
-  /**
-   * Liefert einen Container, in dem fuer jede Farbe ein {@link JLabel}
-   * enthalten ist.
-   * @param table      Tabelle in der die Zelle liegt
-   * @param object     Farben, die in der Zelle darzustellen sind (<b>muss eine
-   *                   Instanz von <code>Color[]</code> sein!!</b>)
-   * @param isSelected gibt an ob die Zelle aktuell selektiert ist
-   * @param hasFocus   gibt an ob die Zelle aktuell den Fokus besitzt
-   * @param row        Tabellenzeile der Zelle
-   * @param column     Tabellenspalte der Zelle
-   * @return eine {@link JComponent} mit horizontal angeordneten {@link JLabel}s
-   */
-  public Component getTableCellRendererComponent(
-                               JTable table,
-                               Object object,
-                               boolean isSelected,
-                               boolean hasFocus,
-                               int row,
-                               int column) {
-    // Methode der Oberklasse (mit Dummy-Farbe) zum erzeugen/setzen
-    // des Rands
-    super.getTableCellRendererComponent(table,null,isSelected,hasFocus,row,column);
-
-    Color[] color = (Color[]) object;
-    // Fuer jede Farbe ein Label erzeugen
-    this.removeAll();
-    for (int i=0; i<color.length; i++) {
-      JLabel label = ColorRenderer.createColorLabel(color[i],null);
-      if ( isBordered )
-        label.setBorder( labelBorder );
-      add(label, new GridBagConstraints(i,0,1,1,1,1.0,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
-    }
-    return this;
-  }
-}
+
+/**
+ * Diese Klasse stellt einen Renderer fuer Tabellenzellen dar, in denen
+ * mehrere Farben (also ein <code>Color[]</code>) dargestellt werden sollen.<br>
+ * Jede Farbe wird durch ein {@link JLabel} in entsprechender Hintergrundfarbe
+ * dargestellt. Die Label werden horizontal angeordnet.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class ColorsRenderer extends ColorRenderer {
+  // Rand um Farb-Label
+  private Border labelBorder = BorderFactory.createLineBorder(Color.BLACK);
+
+  /**
+   * Erzeugt einen neuen Zellen-Renderer.
+   * @param isBordered gibt an ob die Zelle komplett ausgefuellt wird, oder
+   *                   ein Rand erzeugt wird
+   */
+  public ColorsRenderer(boolean isBordered) {
+    super(isBordered);
+    this.setLayout( new GridBagLayout() );
+  }
+
+  /**
+   * Liefert einen Container, in dem fuer jede Farbe ein {@link JLabel}
+   * enthalten ist.
+   * @param table      Tabelle in der die Zelle liegt
+   * @param object     Farben, die in der Zelle darzustellen sind (<b>muss eine
+   *                   Instanz von <code>Color[]</code> sein!!</b>)
+   * @param isSelected gibt an ob die Zelle aktuell selektiert ist
+   * @param hasFocus   gibt an ob die Zelle aktuell den Fokus besitzt
+   * @param row        Tabellenzeile der Zelle
+   * @param column     Tabellenspalte der Zelle
+   * @return eine {@link JComponent} mit horizontal angeordneten {@link JLabel}s
+   */
+  public Component getTableCellRendererComponent(
+                               JTable table,
+                               Object object,
+                               boolean isSelected,
+                               boolean hasFocus,
+                               int row,
+                               int column) {
+    // Methode der Oberklasse (mit Dummy-Farbe) zum erzeugen/setzen
+    // des Rands
+    super.getTableCellRendererComponent(table,null,isSelected,hasFocus,row,column);
+
+    Color[] color = (Color[]) object;
+    // Fuer jede Farbe ein Label erzeugen
+    this.removeAll();
+    for (int i=0; i<color.length; i++) {
+      JLabel label = ColorRenderer.createColorLabel(color[i],null);
+      if ( isBordered )
+        label.setBorder( labelBorder );
+      add(label, new GridBagConstraints(i,0,1,1,1,1.0,GridBagConstraints.CENTER,GridBagConstraints.BOTH,new Insets(0,0,0,0),0,0));
+    }
+    return this;
+  }
+}

Modified: trunk/src/schmitzm/swing/table/ComponentRenderer.java
===================================================================
--- trunk/src/schmitzm/swing/table/ComponentRenderer.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/table/ComponentRenderer.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,16 +1,34 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing.table;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing.table;
-
 import java.awt.Component;
 
 import javax.swing.AbstractButton;
@@ -18,264 +36,264 @@
 import javax.swing.SwingConstants;
 import javax.swing.table.DefaultTableCellRenderer;
 import javax.swing.table.TableCellRenderer;
-
-/**
- * Diese Klasse stellt einen Tabellen-Renderer fuer jede Art von
- * {@link Component}-Objekten dar. Um z.B. einen Button oder eine
- * Checkbox in einer {@link JTable}-Zelle darzustellen, muss mittels der
- * Methode {@link JTable#setDefaultRenderer(Class,TableCellRenderer)} dieser
- * Renderer fuer die entsprechende Zellwert-Klasse zugeordnet werden.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class ComponentRenderer implements TableCellRenderer, SwingConstants {
-  /** Horizontale Ausrichtung der Componente innerhalb der Tabellenzelle
-   *  (Default: {@link SwingConstants#CENTER}). */
-  protected int horAlign = CENTER;
-  /** Vertikale Ausrichtung der Componente innerhalb der Tabellenzelle
-   *  (Default: {@link SwingConstants#CENTER}). */
-  protected int vertAlign = CENTER;
-
-  /**
-   * Erzeugt einen neuen Zellen-Renderer. <b>Die Ausrichtung ist nur relevant
-   * fuer Komponenten vom Typ {@link AbstractButton}!</b>
-   * @param horAlign horizontale Ausrichtung der Komponente innerhalb der
-   *                 Tabellenzelle (RIGHT, LEFT, CENTER, LEADING, TRAILING aus
-   *                 {@link SwingConstants}; Default = CENTER)
-   * @param vertAlign vertikale Ausrichtung der Komponente innerhalb der
-   *                  Tabellenzelle (CENTER, TOP, BOTTOM aus
-   *                  {@link SwingConstants}; Default = CENTER)
-   */
-  public ComponentRenderer(int horAlign, int vertAlign) {
-    super();
-    this.horAlign = horAlign;
-    this.vertAlign = vertAlign;
-  }
-
-  /**
-   * Erzeugt einen neuen Zellen-Renderer.
-   */
-  public ComponentRenderer() {
-    this(CENTER,CENTER);
-  }
-
-  /**
-   * Liefert die horizontale Ausrichtung der Komponente innerhalb der
-   * Tabellenzelle.
-   * @return RIGHT, LEFT, CENTER, LEADING oder TRAILING aus {@link SwingConstants}; Default = CENTER
-   */
-  public int getHorizontalAlignment() {
-    return horAlign;
-  }
-
-  /**
-   * Setzt die horizontale Ausrichtung der Komponente innerhalb der
-   * Tabellenzelle. Wirkt sich nur auf Komponenten vom Typ
-   * {@link AbstractButton} aus!
-   * @param horAlign (RIGHT, LEFT, CENTER, LEADING oder TRAILING aus {@link SwingConstants})
-   */
-  public void setHorizontalAlignment(int horAlign) {
-    this.horAlign = horAlign;
-  }
-
-  /**
-   * Liefert die vertikale Ausrichtung der Komponente innerhalb der
-   * Tabellenzelle.
-   * @return CENTER, TOP oder BOTTOM aus {@link SwingConstants}; Default = CENTER
-   */
-  public int getVerticalAlignment() {
-    return vertAlign;
-  }
-
-  /**
-   * Setzt die vertikale Ausrichtung der Komponente innerhalb der
-   * Tabellenzelle. Wirkt sich nur auf Komponenten vom Typ
-   * {@link AbstractButton} aus!
-   * @param vertAlign (CENTER, TOP oder BOTTOM aus {@link SwingConstants})
-   */
-  public void setVerticalAlignment(int vertAlign) {
-    this.vertAlign = vertAlign;
-  }
-
-  /**
-   * Die von der Methode {@link #createRendererComponent(JTable,Object,boolean,boolean,int,int)}
-   * gelieferte Komponente wird farblich hintelegt, wenn die Tabellenzeile
-   * selektiert ist.
-   * @param table      Tabelle in der die Zelle liegt
-   * @param value      Zu rendernder Wert
-   * @param isSelected gibt an ob die Zelle aktuell selektiert ist
-   * @param hasFocus   gibt an ob die Zelle aktuell den Fokus besitzt
-   * @param row        Tabellenzeile der Zelle
-   * @param column     Tabellenspalte der Zelle
-   */
-  public Component getTableCellRendererComponent(
-                               JTable table,
-                               Object value,
-                               boolean isSelected,
-                               boolean hasFocus,
-                               int row,
-                               int column) {
-    Component rendComp = createRendererComponent(table,value,isSelected,hasFocus,row,column);
-    if ( rendComp instanceof AbstractButton ) {
-      ((AbstractButton)rendComp).setHorizontalAlignment(horAlign);
-      ((AbstractButton)rendComp).setVerticalAlignment(vertAlign);
-    }
-    if ( isSelected ) {
-      rendComp.setBackground(table.getSelectionBackground());
-      rendComp.setForeground(table.getSelectionForeground());
-    }
-    return rendComp;
-  }
-
-  /**
-   * Liefert einfach das zu {@link Component} gecastete Objekt {@code value} zurueck.
-   * Handelt es sich bei <code>comp</code> nicht um ein {@link Component}-Objekt, wird
-   * der {@link DefaultTableCellRenderer} herangezogen.
-   * @param table      Tabelle in der die Zelle liegt
-   * @param value      Zu rendernde Komponente (<b>muss eine
-   *                   Instanz von <code>Component</code> sein!!</b>)
-   * @param isSelected gibt an ob die Zelle aktuell selektiert ist
-   * @param hasFocus   gibt an ob die Zelle aktuell den Fokus besitzt
-   * @param row        Tabellenzeile der Zelle
-   * @param column     Tabellenspalte der Zelle
-   */
-  protected Component createRendererComponent( JTable table,
-                                               Object value,
-                                               boolean isSelected,
-                                               boolean hasFocus,
-                                               int row,
-                                               int column) {
-
-    if ( !(value instanceof Component) )
-      return new DefaultTableCellRenderer().getTableCellRendererComponent(table,value,isSelected,hasFocus,row,column);
-    return (Component)value;
-  }
-
-  /**
-   * Dieser Renderer stellt das jeweilige Objekt in einem {@link javax.swing.JTextField} dar.
-   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-   * @version 1.0
-   */
-  public static class JTextField extends ComponentRenderer {
-    /**
-     * Erzeugt einen neuen Zellen-Renderer in Form einer {@link JCheckBox}.
-     */
-    public JTextField() {
-      super();
-    }
-
-    /**
-     * Liefert ein {@link javax.swing.JTextField}, das als Inhalt den Wert der
-     * Tabellenzelle hat.
-     * @param table      Tabelle in der die Zelle liegt
-     * @param value      Zu renderndes Objekt
-     * @param isSelected gibt an ob die Zelle aktuell selektiert ist
-     * @param hasFocus   gibt an ob die Zelle aktuell den Fokus besitzt
-     * @param row        Tabellenzeile der Zelle
-     * @param column     Tabellenspalte der Zelle
-     */
-    public Component createRendererComponent( JTable table,
-                                              Object value,
-                                              boolean isSelected,
-                                              boolean hasFocus,
-                                              int row,
-                                              int column) {
-      return new javax.swing.JTextField(value != null ? value.toString() : "");
-    }
-  }
-
-  /**
-   * Dieser Renderer stellt das jeweilige Objekt in einer {@link javax.swing.JCheckBox} dar.
-   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-   * @version 1.0
-   */
-  public static class JCheckBox extends ComponentRenderer  {
-    /**
-     * Erzeugt einen neuen Zellen-Renderer in Form einer {@link JCheckBox}.
-     * @param horAlign horizontale Ausrichtung der Checkbox innerhalb der
-     *                 Tabellenzelle (RIGHT, LEFT, CENTER, LEADING, TRAILING aus
-     *                 {@link SwingConstants}; Default = CENTER)
-     * @param vertAlign vertikale Ausrichtung der Checkbox innerhalb der
-     *                  Tabellenzelle (CENTER, TOP, BOTTOM aus
-     *                  {@link SwingConstants}; Default = CENTER)
-     */
-    public JCheckBox(int horAlign, int vertAlign) {
-      super(horAlign, vertAlign);
-    }
-
-    /**
-     * Erzeugt einen neuen Zellen-Renderer in Form einer {@link JCheckBox}.
-     */
-    public JCheckBox() {
-      this(CENTER, CENTER);
-    }
-
-    /**
-     * Liefert eine {@link javax.swing.JCheckBox}, die aktiviert ist, wenn
-     * es sich bei dem darzustellenden Objekt um einen {@link Boolean} handelt,
-     * der den Wert {@code true} hat.
-     * @param table      Tabelle in der die Zelle liegt
-     * @param value      Zu renderndes Objekt
-     * @param isSelected gibt an ob die Zelle aktuell selektiert ist
-     * @param hasFocus   gibt an ob die Zelle aktuell den Fokus besitzt
-     * @param row        Tabellenzeile der Zelle
-     * @param column     Tabellenspalte der Zelle
-     */
-    public Component createRendererComponent( JTable table,
-                                              Object value,
-                                              boolean isSelected,
-                                              boolean hasFocus,
-                                              int row,
-                                              int column) {
-      return new javax.swing.JCheckBox("", value instanceof Boolean && value != null ? (Boolean)value : false);
-    }
-  }
-
-  /**
-   * Dieser Renderer stellt das jeweilige Objekt in Form einer
-   * {@link javax.swing.JComboBox} dar.
-   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-   * @version 1.0
-   */
-  public static class JComboBox extends ComponentRenderer {
-    /**
-     * Erzeugt einen neuen Zellen-Renderer in Form einer {@link JComboBox}.
-     * @param horAlign horizontale Ausrichtung der Combobox innerhalb der
-     *                 Tabellenzelle (RIGHT, LEFT, CENTER, LEADING, TRAILING aus
-     *                 {@link SwingConstants}; Default = CENTER)
-     * @param vertAlign vertikale Ausrichtung der Combobox innerhalb der
-     *                  Tabellenzelle (CENTER, TOP, BOTTOM aus
-     *                  {@link SwingConstants}; Default = CENTER)
-     */
-    public JComboBox(int horAlign, int vertAlign) {
-      super(horAlign, vertAlign);
-    }
-
-    /**
-     * Erzeugt einen neuen Zellen-Renderer in Form einer {@link JComboBox}.
-     */
-    public JComboBox() {
-      this(CENTER, CENTER);
-    }
-
-    /**
-     * Liefert eine {@link javax.swing.JComboBox}, die als Inhalt den Wert der
-     * Tabellenzelle hat.
-     * @param table      Tabelle in der die Zelle liegt
-     * @param value      Zu renderndes Objekt
-     * @param isSelected gibt an ob die Zelle aktuell selektiert ist
-     * @param hasFocus   gibt an ob die Zelle aktuell den Fokus besitzt
-     * @param row        Tabellenzeile der Zelle
-     * @param column     Tabellenspalte der Zelle
-     */
-    public Component createRendererComponent( JTable table,
-                                              Object value,
-                                              boolean isSelected,
-                                              boolean hasFocus,
-                                              int row,
-                                              int column) {
-      return new javax.swing.JComboBox( new Object[] {value} );
-    }
-  }
-
-}
+
+/**
+ * Diese Klasse stellt einen Tabellen-Renderer fuer jede Art von
+ * {@link Component}-Objekten dar. Um z.B. einen Button oder eine
+ * Checkbox in einer {@link JTable}-Zelle darzustellen, muss mittels der
+ * Methode {@link JTable#setDefaultRenderer(Class,TableCellRenderer)} dieser
+ * Renderer fuer die entsprechende Zellwert-Klasse zugeordnet werden.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class ComponentRenderer implements TableCellRenderer, SwingConstants {
+  /** Horizontale Ausrichtung der Componente innerhalb der Tabellenzelle
+   *  (Default: {@link SwingConstants#CENTER}). */
+  protected int horAlign = CENTER;
+  /** Vertikale Ausrichtung der Componente innerhalb der Tabellenzelle
+   *  (Default: {@link SwingConstants#CENTER}). */
+  protected int vertAlign = CENTER;
+
+  /**
+   * Erzeugt einen neuen Zellen-Renderer. <b>Die Ausrichtung ist nur relevant
+   * fuer Komponenten vom Typ {@link AbstractButton}!</b>
+   * @param horAlign horizontale Ausrichtung der Komponente innerhalb der
+   *                 Tabellenzelle (RIGHT, LEFT, CENTER, LEADING, TRAILING aus
+   *                 {@link SwingConstants}; Default = CENTER)
+   * @param vertAlign vertikale Ausrichtung der Komponente innerhalb der
+   *                  Tabellenzelle (CENTER, TOP, BOTTOM aus
+   *                  {@link SwingConstants}; Default = CENTER)
+   */
+  public ComponentRenderer(int horAlign, int vertAlign) {
+    super();
+    this.horAlign = horAlign;
+    this.vertAlign = vertAlign;
+  }
+
+  /**
+   * Erzeugt einen neuen Zellen-Renderer.
+   */
+  public ComponentRenderer() {
+    this(CENTER,CENTER);
+  }
+
+  /**
+   * Liefert die horizontale Ausrichtung der Komponente innerhalb der
+   * Tabellenzelle.
+   * @return RIGHT, LEFT, CENTER, LEADING oder TRAILING aus {@link SwingConstants}; Default = CENTER
+   */
+  public int getHorizontalAlignment() {
+    return horAlign;
+  }
+
+  /**
+   * Setzt die horizontale Ausrichtung der Komponente innerhalb der
+   * Tabellenzelle. Wirkt sich nur auf Komponenten vom Typ
+   * {@link AbstractButton} aus!
+   * @param horAlign (RIGHT, LEFT, CENTER, LEADING oder TRAILING aus {@link SwingConstants})
+   */
+  public void setHorizontalAlignment(int horAlign) {
+    this.horAlign = horAlign;
+  }
+
+  /**
+   * Liefert die vertikale Ausrichtung der Komponente innerhalb der
+   * Tabellenzelle.
+   * @return CENTER, TOP oder BOTTOM aus {@link SwingConstants}; Default = CENTER
+   */
+  public int getVerticalAlignment() {
+    return vertAlign;
+  }
+
+  /**
+   * Setzt die vertikale Ausrichtung der Komponente innerhalb der
+   * Tabellenzelle. Wirkt sich nur auf Komponenten vom Typ
+   * {@link AbstractButton} aus!
+   * @param vertAlign (CENTER, TOP oder BOTTOM aus {@link SwingConstants})
+   */
+  public void setVerticalAlignment(int vertAlign) {
+    this.vertAlign = vertAlign;
+  }
+
+  /**
+   * Die von der Methode {@link #createRendererComponent(JTable,Object,boolean,boolean,int,int)}
+   * gelieferte Komponente wird farblich hintelegt, wenn die Tabellenzeile
+   * selektiert ist.
+   * @param table      Tabelle in der die Zelle liegt
+   * @param value      Zu rendernder Wert
+   * @param isSelected gibt an ob die Zelle aktuell selektiert ist
+   * @param hasFocus   gibt an ob die Zelle aktuell den Fokus besitzt
+   * @param row        Tabellenzeile der Zelle
+   * @param column     Tabellenspalte der Zelle
+   */
+  public Component getTableCellRendererComponent(
+                               JTable table,
+                               Object value,
+                               boolean isSelected,
+                               boolean hasFocus,
+                               int row,
+                               int column) {
+    Component rendComp = createRendererComponent(table,value,isSelected,hasFocus,row,column);
+    if ( rendComp instanceof AbstractButton ) {
+      ((AbstractButton)rendComp).setHorizontalAlignment(horAlign);
+      ((AbstractButton)rendComp).setVerticalAlignment(vertAlign);
+    }
+    if ( isSelected ) {
+      rendComp.setBackground(table.getSelectionBackground());
+      rendComp.setForeground(table.getSelectionForeground());
+    }
+    return rendComp;
+  }
+
+  /**
+   * Liefert einfach das zu {@link Component} gecastete Objekt {@code value} zurueck.
+   * Handelt es sich bei <code>comp</code> nicht um ein {@link Component}-Objekt, wird
+   * der {@link DefaultTableCellRenderer} herangezogen.
+   * @param table      Tabelle in der die Zelle liegt
+   * @param value      Zu rendernde Komponente (<b>muss eine
+   *                   Instanz von <code>Component</code> sein!!</b>)
+   * @param isSelected gibt an ob die Zelle aktuell selektiert ist
+   * @param hasFocus   gibt an ob die Zelle aktuell den Fokus besitzt
+   * @param row        Tabellenzeile der Zelle
+   * @param column     Tabellenspalte der Zelle
+   */
+  protected Component createRendererComponent( JTable table,
+                                               Object value,
+                                               boolean isSelected,
+                                               boolean hasFocus,
+                                               int row,
+                                               int column) {
+
+    if ( !(value instanceof Component) )
+      return new DefaultTableCellRenderer().getTableCellRendererComponent(table,value,isSelected,hasFocus,row,column);
+    return (Component)value;
+  }
+
+  /**
+   * Dieser Renderer stellt das jeweilige Objekt in einem {@link javax.swing.JTextField} dar.
+   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+   * @version 1.0
+   */
+  public static class JTextField extends ComponentRenderer {
+    /**
+     * Erzeugt einen neuen Zellen-Renderer in Form einer {@link JCheckBox}.
+     */
+    public JTextField() {
+      super();
+    }
+
+    /**
+     * Liefert ein {@link javax.swing.JTextField}, das als Inhalt den Wert der
+     * Tabellenzelle hat.
+     * @param table      Tabelle in der die Zelle liegt
+     * @param value      Zu renderndes Objekt
+     * @param isSelected gibt an ob die Zelle aktuell selektiert ist
+     * @param hasFocus   gibt an ob die Zelle aktuell den Fokus besitzt
+     * @param row        Tabellenzeile der Zelle
+     * @param column     Tabellenspalte der Zelle
+     */
+    public Component createRendererComponent( JTable table,
+                                              Object value,
+                                              boolean isSelected,
+                                              boolean hasFocus,
+                                              int row,
+                                              int column) {
+      return new javax.swing.JTextField(value != null ? value.toString() : "");
+    }
+  }
+
+  /**
+   * Dieser Renderer stellt das jeweilige Objekt in einer {@link javax.swing.JCheckBox} dar.
+   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+   * @version 1.0
+   */
+  public static class JCheckBox extends ComponentRenderer  {
+    /**
+     * Erzeugt einen neuen Zellen-Renderer in Form einer {@link JCheckBox}.
+     * @param horAlign horizontale Ausrichtung der Checkbox innerhalb der
+     *                 Tabellenzelle (RIGHT, LEFT, CENTER, LEADING, TRAILING aus
+     *                 {@link SwingConstants}; Default = CENTER)
+     * @param vertAlign vertikale Ausrichtung der Checkbox innerhalb der
+     *                  Tabellenzelle (CENTER, TOP, BOTTOM aus
+     *                  {@link SwingConstants}; Default = CENTER)
+     */
+    public JCheckBox(int horAlign, int vertAlign) {
+      super(horAlign, vertAlign);
+    }
+
+    /**
+     * Erzeugt einen neuen Zellen-Renderer in Form einer {@link JCheckBox}.
+     */
+    public JCheckBox() {
+      this(CENTER, CENTER);
+    }
+
+    /**
+     * Liefert eine {@link javax.swing.JCheckBox}, die aktiviert ist, wenn
+     * es sich bei dem darzustellenden Objekt um einen {@link Boolean} handelt,
+     * der den Wert {@code true} hat.
+     * @param table      Tabelle in der die Zelle liegt
+     * @param value      Zu renderndes Objekt
+     * @param isSelected gibt an ob die Zelle aktuell selektiert ist
+     * @param hasFocus   gibt an ob die Zelle aktuell den Fokus besitzt
+     * @param row        Tabellenzeile der Zelle
+     * @param column     Tabellenspalte der Zelle
+     */
+    public Component createRendererComponent( JTable table,
+                                              Object value,
+                                              boolean isSelected,
+                                              boolean hasFocus,
+                                              int row,
+                                              int column) {
+      return new javax.swing.JCheckBox("", value instanceof Boolean && value != null ? (Boolean)value : false);
+    }
+  }
+
+  /**
+   * Dieser Renderer stellt das jeweilige Objekt in Form einer
+   * {@link javax.swing.JComboBox} dar.
+   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+   * @version 1.0
+   */
+  public static class JComboBox extends ComponentRenderer {
+    /**
+     * Erzeugt einen neuen Zellen-Renderer in Form einer {@link JComboBox}.
+     * @param horAlign horizontale Ausrichtung der Combobox innerhalb der
+     *                 Tabellenzelle (RIGHT, LEFT, CENTER, LEADING, TRAILING aus
+     *                 {@link SwingConstants}; Default = CENTER)
+     * @param vertAlign vertikale Ausrichtung der Combobox innerhalb der
+     *                  Tabellenzelle (CENTER, TOP, BOTTOM aus
+     *                  {@link SwingConstants}; Default = CENTER)
+     */
+    public JComboBox(int horAlign, int vertAlign) {
+      super(horAlign, vertAlign);
+    }
+
+    /**
+     * Erzeugt einen neuen Zellen-Renderer in Form einer {@link JComboBox}.
+     */
+    public JComboBox() {
+      this(CENTER, CENTER);
+    }
+
+    /**
+     * Liefert eine {@link javax.swing.JComboBox}, die als Inhalt den Wert der
+     * Tabellenzelle hat.
+     * @param table      Tabelle in der die Zelle liegt
+     * @param value      Zu renderndes Objekt
+     * @param isSelected gibt an ob die Zelle aktuell selektiert ist
+     * @param hasFocus   gibt an ob die Zelle aktuell den Fokus besitzt
+     * @param row        Tabellenzeile der Zelle
+     * @param column     Tabellenspalte der Zelle
+     */
+    public Component createRendererComponent( JTable table,
+                                              Object value,
+                                              boolean isSelected,
+                                              boolean hasFocus,
+                                              int row,
+                                              int column) {
+      return new javax.swing.JComboBox( new Object[] {value} );
+    }
+  }
+
+}

Modified: trunk/src/schmitzm/swing/table/MutableTable.java
===================================================================
--- trunk/src/schmitzm/swing/table/MutableTable.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/table/MutableTable.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,16 +1,34 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing.table;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing.table;
-
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.MouseAdapter;
@@ -28,72 +46,72 @@
 import javax.swing.table.TableModel;
 
 import schmitzm.swing.event.PopupMenuListener;
-
-
-/**
- * Diese Klasse stellt eine veraenderbare Tabelle dar. Sie erhaelt ein
- * Kontextmenue, ueber das der Tabelle Datensaetze hinzugefuegt, entfernt oder
- * geaendert werden koennen. Zudem reagiert die Tabelle automatisch auf einen
- * Doppelklick mit der Aenderungsaktion.
- * @see MutableTableModel
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class MutableTable extends JTable {
-  /** Konstante fuer den Menuepunkt "Hinzufuegen". */
-  public static final int ITEM_ADD    = 2;
-  /** Konstante fuer den Menuepunkt "Loeschen". */
-  public static final int ITEM_REMOVE = 4;
-  /** Konstante fuer den Menuepunkt "Aendern". */
-  public static final int ITEM_CHANGE = 8;
-  /** Konstante, die alle Menuepunkte beinhaltet. */
-  public static final int ITEM_ALL    = ITEM_ADD | ITEM_REMOVE | ITEM_CHANGE;
-
-  /** Speichert die Datenbasis fuer die Tabelle */
-  protected MutableTableModel model = null;
-
-  /** Speichert, welche Menuepunkte fuer das Kontextmenue aktiv sind */
-  protected int mask = 0;
-
-  /**
-   * Erzeugt eine neue Tabelle.
-   * @param model Datenbasis fuer die Tabelle
-   * @param mask  Definiert die Eintraege im Kontextmenue (logische
-   *              ODER-Verknuepfung der Konstanten <code>ITEM_ADD</code>,
-   *              <code>ITEM_REMOVE</code> und <code>ITEM_CHANGE</code>)
-   * @see #ITEM_ADD
-   * @see #ITEM_REMOVE
-   * @see #ITEM_CHANGE
-   */
-  public MutableTable(MutableTableModel model, int mask) {
-    super(model);
+
+
+/**
+ * Diese Klasse stellt eine veraenderbare Tabelle dar. Sie erhaelt ein
+ * Kontextmenue, ueber das der Tabelle Datensaetze hinzugefuegt, entfernt oder
+ * geaendert werden koennen. Zudem reagiert die Tabelle automatisch auf einen
+ * Doppelklick mit der Aenderungsaktion.
+ * @see MutableTableModel
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class MutableTable extends JTable {
+  /** Konstante fuer den Menuepunkt "Hinzufuegen". */
+  public static final int ITEM_ADD    = 2;
+  /** Konstante fuer den Menuepunkt "Loeschen". */
+  public static final int ITEM_REMOVE = 4;
+  /** Konstante fuer den Menuepunkt "Aendern". */
+  public static final int ITEM_CHANGE = 8;
+  /** Konstante, die alle Menuepunkte beinhaltet. */
+  public static final int ITEM_ALL    = ITEM_ADD | ITEM_REMOVE | ITEM_CHANGE;
+
+  /** Speichert die Datenbasis fuer die Tabelle */
+  protected MutableTableModel model = null;
+
+  /** Speichert, welche Menuepunkte fuer das Kontextmenue aktiv sind */
+  protected int mask = 0;
+
+  /**
+   * Erzeugt eine neue Tabelle.
+   * @param model Datenbasis fuer die Tabelle
+   * @param mask  Definiert die Eintraege im Kontextmenue (logische
+   *              ODER-Verknuepfung der Konstanten <code>ITEM_ADD</code>,
+   *              <code>ITEM_REMOVE</code> und <code>ITEM_CHANGE</code>)
+   * @see #ITEM_ADD
+   * @see #ITEM_REMOVE
+   * @see #ITEM_CHANGE
+   */
+  public MutableTable(MutableTableModel model, int mask) {
+    super(model);
     this.mask  = mask;
-    setModel(model);
-
-    // MouseListener fuer PopupMenu
-    this.addMouseListener( createPopupMenuListener(mask) );
-    getTableHeader().addMouseListener( createPopupMenuListener(mask) );
-
-    // MouseListener fuer Doppelklick
-    this.addMouseListener(new MouseAdapter() {
-      public void mouseClicked(MouseEvent e) {
-        if (e.getButton() == MouseEvent.BUTTON1 &&
-            e.getClickCount() == 2)
-          performDoubleClick();
-      }
+    setModel(model);
+
+    // MouseListener fuer PopupMenu
+    this.addMouseListener( createPopupMenuListener(mask) );
+    getTableHeader().addMouseListener( createPopupMenuListener(mask) );
+
+    // MouseListener fuer Doppelklick
+    this.addMouseListener(new MouseAdapter() {
+      public void mouseClicked(MouseEvent e) {
+        if (e.getButton() == MouseEvent.BUTTON1 &&
+            e.getClickCount() == 2)
+          performDoubleClick();
+      }
     });
-  }
-
-  /**
-   * Erzeugt eine neue Tabelle mit komplettem Kontextmenue.
-   * @param model Datenbasis fuer die Tabelle
-   * @see #ITEM_ALL
-   */
-  public MutableTable(MutableTableModel model) {
-    this(model,ITEM_ALL);
   }
 
   /**
+   * Erzeugt eine neue Tabelle mit komplettem Kontextmenue.
+   * @param model Datenbasis fuer die Tabelle
+   * @see #ITEM_ALL
+   */
+  public MutableTable(MutableTableModel model) {
+    this(model,ITEM_ALL);
+  }
+
+  /**
    * Setzt das Datenmodell fuer die Tabelle und ruft {@link MutableTableModel#initTable(JTable)}
    * auf.
    * @exception UnsupportedOperationException falls kein {@link MutableTableModel}
@@ -106,241 +124,241 @@
     super.setModel(model);
     this.model = (MutableTableModel)model;
     this.model.initTable(this);
-  }
-
-  /**
-   * Erzeugt einen {@link MouseListener} der bei einem Popup-Signal (z.B.
-   * Rechtsklick) das Tabellen-Menue oeffnet. In diesem sind alle Menuepunkte
-   * (Aendern, Loeschen, Hinzufuegen) enthalten.
-   * @see #createPopupMenuListener(int)
-   * @see #ITEM_ALL
-   */
-  public MouseListener createPopupMenuListener() {
-    return createPopupMenuListener(ITEM_ALL);
-  }
-
-  /**
-   * Erzeugt einen {@link MouseListener} der bei einem Popup-Signal (z.B.
-   * Rechtsklick) das Tabellen-Kontextmenue oeffnet.
-   * @param mask  Definiert die Eintraege im Kontextmenue (logische
-   *              ODER-Verknuepfung der Konstanten <code>ITEM_ADD</code>,
-   *              <code>ITEM_REMOVE</code> und <code>ITEM_CHANGE</code>)
-   * @see #ITEM_ADD
-   * @see #ITEM_REMOVE
-   * @see #ITEM_CHANGE
-   */
-  public MouseListener createPopupMenuListener(int mask) {
-    return new PopupMenuListener( createPopupMenu(mask).getPopupMenu() );
-  }
-
-  /**
-   * Erzeugt eine Instanz des {@link PopupMenu}. Unterklassen koennen diese
-   * Methode ueberschreiben, um das Menu zu erweitern.
-   * @param mask  Definiert die Eintraege im Kontextmenue (logische
-   *              ODER-Verknuepfung der Konstanten <code>ITEM_ADD</code>,
-   *              <code>ITEM_REMOVE</code> und <code>ITEM_CHANGE</code>)
-   * @see #ITEM_ADD
-   * @see #ITEM_REMOVE
-   * @see #ITEM_CHANGE
-   */
-  protected PopupMenu createPopupMenu(int mask) {
-    return new PopupMenu(this,mask);
-  }
-
-  /**
-   * Liefert die Bit-Maske, welche Punkt im Kontextmenue aktiv sind.
-   * @see #ITEM_ADD
-   * @see #ITEM_REMOVE
-   * @see #ITEM_CHANGE
-   * @see #ITEM_ALL
-   */
-  public int getMask() {
-    return mask;
-  }
-
-  /**
-   * Wird aufgerufen, wenn der Menuepunkt "Ändern" gewaehlt wird.
-   * Ruft fuer jede selektierte Zelle {@link MutableTableModel#performChangeData(int,int) MutableTableModel#performChangeData(..)}
-   * auf. Ist nur eine zeilenweise Auswahl in der Tabelle erlaubt, so
-   * wird die obige Methode nur fuer jede selektierte Zeile aufgerufen.
-   * Der Aufrufparameter fuer die Spalte ist in diesem Fall die Spalte, auf die geklickt
-   * wurde.<br>
-   * Erwirkt anschliessend ein {@link AbstractTableModel#fireTableDataChanged()}
-   * @see #setRowSelectionAllowed(boolean)
-   */
-  protected void performChange() {
-    int selCol[] = this.getSelectedColumns();
-    int selRow[] = this.getSelectedRows();
-
-    for (int r=0; r<selRow.length; r++) {
-      // werden Zellen einzeln selektiert, wird fuer jede Zelle
-      // einzeln die Aenderungsaktion ausgefuehrt, sonst nur einmal
-      // pro Zeile
-      if ( !this.rowSelectionAllowed )
-        for (int c=0; c<selCol.length; c++)
-          model.performChangeData(selRow[r],selCol[c]);
-      else
-        // Als Spalte wird diejenige angegeben, auf die geklickt wurde
-        model.performChangeData(selRow[r], this.getSelectedColumn());
-    }
-    model.fireTableDataChanged();
-  }
-
-  /**
-   * Wird aufgerufen, wenn der Menuepunkt "Löschen" gewaehlt wird.
-   * Ruft fuer jede selektierte Zeile {@link MutableTableModel#performRemoveRow(int) MutableTableModel#performRemoveRow(..)}
-   * auf. Dabei wird <b>rueckwaerts</b> vorgegangen - also die letzte selektierte
-   * Zeile zuerst -, damit der Zeilenindex ueber alle
-   * {@link MutableTableModel#performRemoveRow(int)}-Aufrufe konsistent bleibt.
-   * Erwirkt anschliessend automatisch ein {@link AbstractTableModel#fireTableDataChanged()}
-
-   */
-  protected void performRemove() {
-    int selRow[] = this.getSelectedRows();
-    for (int r=selRow.length-1; r>=0; r--)
-      model.performRemoveRow(selRow[r]);
-    model.fireTableDataChanged();
-  }
-
-  /**
-   * Wird aufgerufen, wenn der Menuepunkt "Hinzufügen" gewaehlt wird.
-   * Ruft {@link MutableTableModel#performAddRow() MutableTableModel#performAddRow()}
-   * auf.<br>
-   * Erwirkt anschliessend automatisch ein {@link AbstractTableModel#fireTableDataChanged()}
-   */
-  protected void performAdd() {
-    model.performAddRow();
-    model.fireTableDataChanged();
-  }
-
-  /**
-   * Wird aufgerufen, wenn ein Doppelklick auf die Tabelle vorgenommen wird.
-   * Standardmaessig wird {@link #performChange()} aufgerufen (sofern
-   * der Aendern-Menuepunkt aktiv ist!).
-   * Unterklassen koennen diese Methode ueberschreiben, um diesem Ereignis
-   * eins andere Aktion zuzuweisen oder das Ereignis gaenzlich zu unterdruecken.
-   */
-  public void performDoubleClick() {
-    if ( (mask & ITEM_CHANGE) > 0 )
-      performChange();
-  }
-
-  /**
-   * Erzeugt ein {@link JScrollPane} fuer die Tabelle. Dieses erhaelt automatisch
-   * den gleichen ToolTip-Text und Popupmenue-Listener wie die Tabelle.
-   * Der Anwender kann somit auch auf das ScrollPane klicken, um die Tabellen-Optionen
-   * anzuwaehlen.
-   */
-  public JScrollPane createScrollPane() {
-    JScrollPane scrollPane = new JScrollPane( this );
-    scrollPane.setToolTipText( this.getToolTipText() );
-    scrollPane.addMouseListener( this.createPopupMenuListener( this.getMask() ) );
-    return scrollPane;
-  }
-
-  /**
-   * Diese Klasse stellt das Kontextmenue fuer einen {@link MutableTable}
-   * dar.
-   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-   * @version 1.0
-   */
-  protected class PopupMenu extends JMenu {
-    /** Menueeintrag fuer Aendern-Aktion */
-    protected JMenuItem changeItem = new JMenuItem("Ändern");
-    /** Menueeintrag fuer Entfernen-Aktion */
-    protected JMenuItem removeItem = new JMenuItem("Entfernen");
-    /** Menueeintrag fuer Hinzufuegen-Aktion */
-    protected JMenuItem addItem = new JMenuItem("Hinzufügen");
-
-    private MutableTable table = null;
-
-    /**
-     * Erzeugt ein neues Kontextmenue.
-     * @param table Tabelle auf die sich die Aktionen des Menus beziehen
-     * @param mask  Definiert die Eintraege im Kontextmenue (logische
-     *              ODER-Verknuepfung der Konstanten <code>ITEM_ADD</code>,
-     *              <code>ITEM_REMOVE</code> und <code>ITEM_CHANGE</code>)
-     * @see #ITEM_ADD
-     * @see #ITEM_REMOVE
-     * @see #ITEM_CHANGE
-     */
-    public PopupMenu(final MutableTable table, int mask) {
-      super();
-      this.table = table;
-      changeItem.addActionListener( new ActionListener() {
-        public void actionPerformed(ActionEvent e) {
-          table.performChange();
-        }
-      });
-      addItem.addActionListener( new ActionListener() {
-        public void actionPerformed(ActionEvent e) {
-          table.performAdd();
-        }
-      });
-      removeItem.addActionListener( new ActionListener() {
-        public void actionPerformed(ActionEvent e) {
-          table.performRemove();
-        }
-      });
-
-      // Menue-Punkte hinzufuegen
-      if ( (mask & ITEM_CHANGE) > 0 )
-        this.add( changeItem );
-      if ( (mask & ITEM_ADD) > 0 )
-        this.add( addItem );
-      if ( (mask & ITEM_REMOVE) > 0 )
-        this.add( removeItem );
-
-      this.addMenuListener( new MenuListener() {
-        public void menuCanceled(MenuEvent e) {}
-        public void menuDeselected(MenuEvent e) {}
-        public void menuSelected(MenuEvent e) {
-          setEnabled(ITEM_REMOVE,table.getSelectedRowCount() > 0);
-          setEnabled(ITEM_CHANGE,table.getSelectedRowCount() > 0);
-        }
-
-      });
-    }
-
-    /**
-     * Erzeugt ein komplettes Kontextmenue mit allen moeglichen Aktionen.
-     */
-    public PopupMenu(final MutableTable table) {
-      this(table,ITEM_ALL);
-    }
-
-    /**
-     * (De)aktiviert ein oder mehrere Menueintraege.
-     * @param mask definiert die betroffenen Eintraege (logische
-     *              ODER-Verknuepfung der Konstanten <code>ITEM_ADD</code>,
-     *              <code>ITEM_REMOVE</code> und <code>ITEM_CHANGE</code>)
-     * @param enabled bestimmt ob der Eintrag aktiviert oder deaktiviert wird
-     */
-    public void setEnabled(int mask, boolean enabled) {
-      if ( (mask & ITEM_CHANGE) > 0 )
-        changeItem.setEnabled( enabled );
-      if ( (mask & ITEM_ADD) > 0 )
-        addItem.setEnabled( enabled );
-      if ( (mask & ITEM_REMOVE) > 0 )
-        removeItem.setEnabled( enabled );
-    }
-
-    /**
-     * Erzeugt ein dem Menue entsprechendes {@link JPopupMenu}.
-     */
-    public JPopupMenu getPopupMenu() {
-      JPopupMenu menu = super.getPopupMenu();
-      menu.addPopupMenuListener( new javax.swing.event.PopupMenuListener() {
-        public void popupMenuCanceled(javax.swing.event.PopupMenuEvent e) {}
-        public void popupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent e) {}
-        public void popupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent e) {
-          setEnabled(ITEM_REMOVE,table.getSelectedRowCount() > 0);
-          setEnabled(ITEM_CHANGE,table.getSelectedRowCount() > 0);
-        }
-      });
-      return menu;
-    }
-
-  }
-
-}
+  }
+
+  /**
+   * Erzeugt einen {@link MouseListener} der bei einem Popup-Signal (z.B.
+   * Rechtsklick) das Tabellen-Menue oeffnet. In diesem sind alle Menuepunkte
+   * (Aendern, Loeschen, Hinzufuegen) enthalten.
+   * @see #createPopupMenuListener(int)
+   * @see #ITEM_ALL
+   */
+  public MouseListener createPopupMenuListener() {
+    return createPopupMenuListener(ITEM_ALL);
+  }
+
+  /**
+   * Erzeugt einen {@link MouseListener} der bei einem Popup-Signal (z.B.
+   * Rechtsklick) das Tabellen-Kontextmenue oeffnet.
+   * @param mask  Definiert die Eintraege im Kontextmenue (logische
+   *              ODER-Verknuepfung der Konstanten <code>ITEM_ADD</code>,
+   *              <code>ITEM_REMOVE</code> und <code>ITEM_CHANGE</code>)
+   * @see #ITEM_ADD
+   * @see #ITEM_REMOVE
+   * @see #ITEM_CHANGE
+   */
+  public MouseListener createPopupMenuListener(int mask) {
+    return new PopupMenuListener( createPopupMenu(mask).getPopupMenu() );
+  }
+
+  /**
+   * Erzeugt eine Instanz des {@link PopupMenu}. Unterklassen koennen diese
+   * Methode ueberschreiben, um das Menu zu erweitern.
+   * @param mask  Definiert die Eintraege im Kontextmenue (logische
+   *              ODER-Verknuepfung der Konstanten <code>ITEM_ADD</code>,
+   *              <code>ITEM_REMOVE</code> und <code>ITEM_CHANGE</code>)
+   * @see #ITEM_ADD
+   * @see #ITEM_REMOVE
+   * @see #ITEM_CHANGE
+   */
+  protected PopupMenu createPopupMenu(int mask) {
+    return new PopupMenu(this,mask);
+  }
+
+  /**
+   * Liefert die Bit-Maske, welche Punkt im Kontextmenue aktiv sind.
+   * @see #ITEM_ADD
+   * @see #ITEM_REMOVE
+   * @see #ITEM_CHANGE
+   * @see #ITEM_ALL
+   */
+  public int getMask() {
+    return mask;
+  }
+
+  /**
+   * Wird aufgerufen, wenn der Menuepunkt "Ändern" gewaehlt wird.
+   * Ruft fuer jede selektierte Zelle {@link MutableTableModel#performChangeData(int,int) MutableTableModel#performChangeData(..)}
+   * auf. Ist nur eine zeilenweise Auswahl in der Tabelle erlaubt, so
+   * wird die obige Methode nur fuer jede selektierte Zeile aufgerufen.
+   * Der Aufrufparameter fuer die Spalte ist in diesem Fall die Spalte, auf die geklickt
+   * wurde.<br>
+   * Erwirkt anschliessend ein {@link AbstractTableModel#fireTableDataChanged()}
+   * @see #setRowSelectionAllowed(boolean)
+   */
+  protected void performChange() {
+    int selCol[] = this.getSelectedColumns();
+    int selRow[] = this.getSelectedRows();
+
+    for (int r=0; r<selRow.length; r++) {
+      // werden Zellen einzeln selektiert, wird fuer jede Zelle
+      // einzeln die Aenderungsaktion ausgefuehrt, sonst nur einmal
+      // pro Zeile
+      if ( !this.rowSelectionAllowed )
+        for (int c=0; c<selCol.length; c++)
+          model.performChangeData(selRow[r],selCol[c]);
+      else
+        // Als Spalte wird diejenige angegeben, auf die geklickt wurde
+        model.performChangeData(selRow[r], this.getSelectedColumn());
+    }
+    model.fireTableDataChanged();
+  }
+
+  /**
+   * Wird aufgerufen, wenn der Menuepunkt "Löschen" gewaehlt wird.
+   * Ruft fuer jede selektierte Zeile {@link MutableTableModel#performRemoveRow(int) MutableTableModel#performRemoveRow(..)}
+   * auf. Dabei wird <b>rueckwaerts</b> vorgegangen - also die letzte selektierte
+   * Zeile zuerst -, damit der Zeilenindex ueber alle
+   * {@link MutableTableModel#performRemoveRow(int)}-Aufrufe konsistent bleibt.
+   * Erwirkt anschliessend automatisch ein {@link AbstractTableModel#fireTableDataChanged()}
+
+   */
+  protected void performRemove() {
+    int selRow[] = this.getSelectedRows();
+    for (int r=selRow.length-1; r>=0; r--)
+      model.performRemoveRow(selRow[r]);
+    model.fireTableDataChanged();
+  }
+
+  /**
+   * Wird aufgerufen, wenn der Menuepunkt "Hinzufügen" gewaehlt wird.
+   * Ruft {@link MutableTableModel#performAddRow() MutableTableModel#performAddRow()}
+   * auf.<br>
+   * Erwirkt anschliessend automatisch ein {@link AbstractTableModel#fireTableDataChanged()}
+   */
+  protected void performAdd() {
+    model.performAddRow();
+    model.fireTableDataChanged();
+  }
+
+  /**
+   * Wird aufgerufen, wenn ein Doppelklick auf die Tabelle vorgenommen wird.
+   * Standardmaessig wird {@link #performChange()} aufgerufen (sofern
+   * der Aendern-Menuepunkt aktiv ist!).
+   * Unterklassen koennen diese Methode ueberschreiben, um diesem Ereignis
+   * eins andere Aktion zuzuweisen oder das Ereignis gaenzlich zu unterdruecken.
+   */
+  public void performDoubleClick() {
+    if ( (mask & ITEM_CHANGE) > 0 )
+      performChange();
+  }
+
+  /**
+   * Erzeugt ein {@link JScrollPane} fuer die Tabelle. Dieses erhaelt automatisch
+   * den gleichen ToolTip-Text und Popupmenue-Listener wie die Tabelle.
+   * Der Anwender kann somit auch auf das ScrollPane klicken, um die Tabellen-Optionen
+   * anzuwaehlen.
+   */
+  public JScrollPane createScrollPane() {
+    JScrollPane scrollPane = new JScrollPane( this );
+    scrollPane.setToolTipText( this.getToolTipText() );
+    scrollPane.addMouseListener( this.createPopupMenuListener( this.getMask() ) );
+    return scrollPane;
+  }
+
+  /**
+   * Diese Klasse stellt das Kontextmenue fuer einen {@link MutableTable}
+   * dar.
+   * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+   * @version 1.0
+   */
+  protected class PopupMenu extends JMenu {
+    /** Menueeintrag fuer Aendern-Aktion */
+    protected JMenuItem changeItem = new JMenuItem("Ändern");
+    /** Menueeintrag fuer Entfernen-Aktion */
+    protected JMenuItem removeItem = new JMenuItem("Entfernen");
+    /** Menueeintrag fuer Hinzufuegen-Aktion */
+    protected JMenuItem addItem = new JMenuItem("Hinzufügen");
+
+    private MutableTable table = null;
+
+    /**
+     * Erzeugt ein neues Kontextmenue.
+     * @param table Tabelle auf die sich die Aktionen des Menus beziehen
+     * @param mask  Definiert die Eintraege im Kontextmenue (logische
+     *              ODER-Verknuepfung der Konstanten <code>ITEM_ADD</code>,
+     *              <code>ITEM_REMOVE</code> und <code>ITEM_CHANGE</code>)
+     * @see #ITEM_ADD
+     * @see #ITEM_REMOVE
+     * @see #ITEM_CHANGE
+     */
+    public PopupMenu(final MutableTable table, int mask) {
+      super();
+      this.table = table;
+      changeItem.addActionListener( new ActionListener() {
+        public void actionPerformed(ActionEvent e) {
+          table.performChange();
+        }
+      });
+      addItem.addActionListener( new ActionListener() {
+        public void actionPerformed(ActionEvent e) {
+          table.performAdd();
+        }
+      });
+      removeItem.addActionListener( new ActionListener() {
+        public void actionPerformed(ActionEvent e) {
+          table.performRemove();
+        }
+      });
+
+      // Menue-Punkte hinzufuegen
+      if ( (mask & ITEM_CHANGE) > 0 )
+        this.add( changeItem );
+      if ( (mask & ITEM_ADD) > 0 )
+        this.add( addItem );
+      if ( (mask & ITEM_REMOVE) > 0 )
+        this.add( removeItem );
+
+      this.addMenuListener( new MenuListener() {
+        public void menuCanceled(MenuEvent e) {}
+        public void menuDeselected(MenuEvent e) {}
+        public void menuSelected(MenuEvent e) {
+          setEnabled(ITEM_REMOVE,table.getSelectedRowCount() > 0);
+          setEnabled(ITEM_CHANGE,table.getSelectedRowCount() > 0);
+        }
+
+      });
+    }
+
+    /**
+     * Erzeugt ein komplettes Kontextmenue mit allen moeglichen Aktionen.
+     */
+    public PopupMenu(final MutableTable table) {
+      this(table,ITEM_ALL);
+    }
+
+    /**
+     * (De)aktiviert ein oder mehrere Menueintraege.
+     * @param mask definiert die betroffenen Eintraege (logische
+     *              ODER-Verknuepfung der Konstanten <code>ITEM_ADD</code>,
+     *              <code>ITEM_REMOVE</code> und <code>ITEM_CHANGE</code>)
+     * @param enabled bestimmt ob der Eintrag aktiviert oder deaktiviert wird
+     */
+    public void setEnabled(int mask, boolean enabled) {
+      if ( (mask & ITEM_CHANGE) > 0 )
+        changeItem.setEnabled( enabled );
+      if ( (mask & ITEM_ADD) > 0 )
+        addItem.setEnabled( enabled );
+      if ( (mask & ITEM_REMOVE) > 0 )
+        removeItem.setEnabled( enabled );
+    }
+
+    /**
+     * Erzeugt ein dem Menue entsprechendes {@link JPopupMenu}.
+     */
+    public JPopupMenu getPopupMenu() {
+      JPopupMenu menu = super.getPopupMenu();
+      menu.addPopupMenuListener( new javax.swing.event.PopupMenuListener() {
+        public void popupMenuCanceled(javax.swing.event.PopupMenuEvent e) {}
+        public void popupMenuWillBecomeInvisible(javax.swing.event.PopupMenuEvent e) {}
+        public void popupMenuWillBecomeVisible(javax.swing.event.PopupMenuEvent e) {
+          setEnabled(ITEM_REMOVE,table.getSelectedRowCount() > 0);
+          setEnabled(ITEM_CHANGE,table.getSelectedRowCount() > 0);
+        }
+      });
+      return menu;
+    }
+
+  }
+
+}

Modified: trunk/src/schmitzm/swing/table/MutableTableModel.java
===================================================================
--- trunk/src/schmitzm/swing/table/MutableTableModel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/table/MutableTableModel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,60 +1,78 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing.table;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing.table;
-
 import javax.swing.JTable;
 import javax.swing.table.TableModel;
-
-/**
- * Diese Klasse erweitert das {@link TableModel} um die 3
- * Aktionen
- * <ul>
- * <li>Hinzufuegen einer Tabellenzeile</li>
- * <li>Loeschen einer Tabellenzeile</li>
- * <li>Aendern einer Tabellenzelle</li>
- * </ul>
- * Diese Aktionsaufforderungen koennen somit von ausserhalb (z.B. durch ein Menue)
- * an das TableModel herangetragen werden.
- * @see MutableTable
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
+
+/**
+ * Diese Klasse erweitert das {@link TableModel} um die 3
+ * Aktionen
+ * <ul>
+ * <li>Hinzufuegen einer Tabellenzeile</li>
+ * <li>Loeschen einer Tabellenzeile</li>
+ * <li>Aendern einer Tabellenzelle</li>
+ * </ul>
+ * Diese Aktionsaufforderungen koennen somit von ausserhalb (z.B. durch ein Menue)
+ * an das TableModel herangetragen werden.
+ * @see MutableTable
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
 public interface MutableTableModel extends TableModel {
-  /**
-   * Fordert das TableModel auf, eine bestimmte Zeile zu loeschen.
-   * @param row Zeilennummer
-   */
-  public void performRemoveRow(int row);
-
-  /**
-   * Fordert das TableModel auf, eine Zeile hinzuzufuegen. Das TableModel ist
-   * dafuer verwantwortlich, die benoetigten Daten zu ermitteln (z.B. ueber
-   * einen Anwender-Dialog).
-   */
-  public void performAddRow();
-
-  /**
-   * Fordert das TableModel auf, eine Tabellenzelle zu aendern. Das TableModel ist
-   * dafuer verwantwortlich, die benoetigten Daten zu ermitteln (z.B. ueber
-   * einen Anwender-Dialog).
-   * @param row Zeilennummer
-   * @param col Spalzennummer
-   */
+  /**
+   * Fordert das TableModel auf, eine bestimmte Zeile zu loeschen.
+   * @param row Zeilennummer
+   */
+  public void performRemoveRow(int row);
+
+  /**
+   * Fordert das TableModel auf, eine Zeile hinzuzufuegen. Das TableModel ist
+   * dafuer verwantwortlich, die benoetigten Daten zu ermitteln (z.B. ueber
+   * einen Anwender-Dialog).
+   */
+  public void performAddRow();
+
+  /**
+   * Fordert das TableModel auf, eine Tabellenzelle zu aendern. Das TableModel ist
+   * dafuer verwantwortlich, die benoetigten Daten zu ermitteln (z.B. ueber
+   * einen Anwender-Dialog).
+   * @param row Zeilennummer
+   * @param col Spalzennummer
+   */
   public void performChangeData(int row, int col);
 
   /**
    * Initiert ein Neu-Aufbauen der Tabelle.
    */
-  public void fireTableDataChanged();
+  public void fireTableDataChanged();
 
   /**
    * Wird von {@link MutableTable#setModel(TableModel)}
@@ -65,4 +83,4 @@
    */
   public void initTable(JTable table);
 
-}
+}

Modified: trunk/src/schmitzm/swing/table/PipedTableModel.java
===================================================================
--- trunk/src/schmitzm/swing/table/PipedTableModel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/table/PipedTableModel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,25 +1,44 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.swing.table;
-
-import javax.swing.table.TableModel;
-
-/**
- * Interface for all table models which encapsulate another {@link TableModel}.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- */
-public interface PipedTableModel {
-  /**
-   * Returns the original {@link TableModel}.
-   */
-  public TableModel getPipedModel();
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing.table;
+
+import javax.swing.table.TableModel;
+
+/**
+ * Interface for all table models which encapsulate another {@link TableModel}.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ */
+public interface PipedTableModel {
+  /**
+   * Returns the original {@link TableModel}.
+   */
+  public TableModel getPipedModel();
+
+}

Modified: trunk/src/schmitzm/swing/table/SelectionTableModel.java
===================================================================
--- trunk/src/schmitzm/swing/table/SelectionTableModel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/table/SelectionTableModel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,321 +1,340 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package schmitzm.swing.table;
-
-import javax.swing.JTable;
-import javax.swing.event.TableModelListener;
-import javax.swing.table.AbstractTableModel;
-import javax.swing.table.TableModel;
-
-import schmitzm.swing.SelectableJTable;
-
-/**
- * This table model extends an other {@link TableModel} by inserting an
- * additional column 0 which shows and controls the row selection.
- * To realize this functionality it is necessary to connect this table model
- * to an explicit {@link JTable}. Besides it is necessary that this table
- * is a {@link SelectableJTable} to overcome the "normal" click behavior (clear
- * selection when no Ctrl/Shift key is hold), when clicking the selection column. 
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- */
-public class SelectionTableModel extends AbstractTableModel implements PipedTableModel {
-
-  /** Holds the table which controls the selection. */
-  protected SelectableJTable table = null;
-  /** Holds the base data. */
-  protected TableModel model = null;
-//!! SOLVED BY USING SelectableJTable !!
-//  /** Used to realize the selection column. */
-//  protected SelectionRestorer selectionRestorer = null;
-  
-  
-  /**
-   * Creates a new table model
-   * @param model provides the data
-   * @param table used to determine the row selection 
-   */
-  public SelectionTableModel(TableModel model, SelectableJTable table) {
-    super();
-    this.model = model;
-    this.table = table;
-    table.getColumnModel().setColumnSelectionAllowed(false);
-    
-//!! SOLVED BY USING SelectableJTable !!
-//    // Goal: By selection column cells, rows should be selected individually,
-//    //       without holding Strg/Shift key.
-//    // Problem: Also on a click in the selection column, the selection
-//    //          is first cleared
-//    // Solution: After every key stroke and every mouse click, the current
-//    //           selection is remembered. On click on selection column
-//    //           (the selection is already cleared!) the selection is
-//    //           restored. After that the click (TableModel.setValue(..)) is
-//    //           progressed, which extends the selection.
-//    this.selectionRestorer = new SelectionRestorer(table);
-  }
-
-//!! SOLVED BY USING SelectableJTable !!
-//  /**
-//   * Forces a update of the {@link SelectionRestorer} to renew the
-//   * remembered selected cells.
-//   */
-//  public void updateSelectionRestorer() {
-//    if ( selectionRestorer != null )
-//      selectionRestorer.update();
-//  }
-  
-  /**
-   * Returns the original {@link TableModel}.
-   */
-  @Override
-  public TableModel getPipedModel() {
-    return model;
-  }
-  
-  /**
-   * Adds a listener to the list that's notified each time a change
-   * to the data model occurs.
-   */
-  @Override
-  public void addTableModelListener(TableModelListener listener) {
-    model.addTableModelListener(listener);
-  }
-  
-  /**
-   * Removes a listener from the list that's notified each time a change
-   * to the data model occurs.
-   */
-  @Override
-  public void removeTableModelListener(TableModelListener listener) {
-    model.removeTableModelListener(listener);
-  }
-
-  /**
-   * Returns the type of a column.
-   * @return {@code Boolean.class} for column 0
-   */
-  @Override
-  public Class<?> getColumnClass(int col) {
-    if ( col == 0 )
-      return Boolean.class;
-   return model.getColumnClass(col - 1); 
-  }
-  
-  /**
-   * Returns the type of a column.
-   * @return {@code Boolean.class} for column 0
-   */
-  @Override
-  public int getColumnCount() {
-   return model.getColumnCount() + 1; 
-  }
-  
-  /**
-   * Returns the name of a column.
-   * @return empty string for column 0
-   */
-  @Override
-  public String getColumnName(int col) {
-    if ( col == 0 )
-      return "";
-   return model.getColumnName(col - 1); 
-  }
-  
-  /**
-   * Returns the number of rows in the model.
-   */
-  @Override
-  public int getRowCount() {
-    return model.getRowCount();
-  }
-
-  /**
-   * Returns the value for a cell.
-   * @param row row index
-   * @param col column index
-   */
-  @Override
-  public Object getValueAt(int row, int col) {
-    if ( col == 0 )
-      return table.isRowSelected( table.convertRowIndexToView(row) );
-    return model.getValueAt(row, col - 1);
-  }
-  
-  /**
-   * Sets a value for a cell.
-   * @param value new cell value
-   * @param row row index
-   * @param col column index
-   */
-  @Override
-  public void setValueAt(Object value, int row, int col) {
-    if ( col == 0 ) {
-      if ( value instanceof Boolean ) {
-        boolean select   = ((Boolean)value).booleanValue();
-        int     tableRow = table.convertRowIndexToView(row);
-        if ( select )
-          table.addRowSelectionInterval(tableRow, tableRow);
-        else
-          table.removeRowSelectionInterval(tableRow, tableRow);
-      }
-    } else
-      model.setValueAt(value, row, col - 1);
-  }
-
-  /**
-   * Returns the value for a cell.
-   * @param row row index
-   * @param col column index
-   * @param {@code true} for column 0
-   */
-  @Override
-  public boolean isCellEditable(int row, int col) {
-    if ( col == 0 )
-      return true;
-    return model.isCellEditable(row, col - 1);
-  }
-
-// !!! BY USING SelectableJTable THIS PROCEDURE IS NOT NEEDED ANYMORE !!!  
-//  /**
-//   * This listener must be added as {@link MouseListener} and {@link KeyListener}.
-//   * It stored the current table selection (rows) on every mouse click and key
-//   * stroke. On mouse click on selection column 0, the remembered selection
-//   * is restored to avoid the selection clear.<br><br>
-//   * 
-//   * <b>Goal:</b> By selection column cells, rows should be selected individually,
-//   *              without holding Strg/Shift key.<br>
-//   * <b>Problem:</b> Also on a click in the selection column, the selection
-//   *                 is first cleared.<br>
-//   * <b>Solution:</b> After every key stroke and every mouse click, the current
-//   *                  selection is remembered. On click on selection column
-//   *                  (the selection is already cleared!) the selection is
-//   *                  restored. After that the click (TableModel.setValue(..)) is
-//   *                  progressed, which extends the selection.
-//   */
-//  private static class SelectionRestorer extends MouseAdapter implements KeyListener, ListSelectionListener {
-//    /** Holds the table the selection is remembered from. */
-//    protected JTable table = null;
-//    /** Holds the remembered rows according to the model. */
-//    protected int[] selectedModelRows = null;
-//
-//    /**
-//     * Created a new selection rememberer and adds the listener to
-//     * the {@link JTable}.
-//     * @param table a table
-//     */
-//    public SelectionRestorer(JTable table) {
-//      super();
-//      connect(table);
-//    }
-//
-//    /**
-//     * Connects the {@link SelectionRestorer} to a {@link JTable}
-//     * as {@link MouseListener}, {@link KeyListener} and {@link ListSelectionListener}.
-//     * @param table a table
-//     */
-//    protected void connect(JTable table) {
-//      this.table = table;
-//      // remove all previously connected SelectionRestorers
-//      disconnect();
-//      // add Listeners
-//      table.addMouseListener(this);
-//      table.addKeyListener(this);
-//      table.getSelectionModel().addListSelectionListener(this);
-//    }
-//    
-//    /**
-//     * Disconnects the {@link SelectionRestorer} from the {@link JTable}.
-//     */
-//    public void disconnect() {
-//      // remove all previously connected SelectionRestorers
-//      SelectionRestorer[] selRest = table.getListeners(SelectionRestorer.class);
-//      for (SelectionRestorer selectionRestorer : selRest) {
-//        table.removeMouseListener(selectionRestorer);
-//        table.removeKeyListener(selectionRestorer);
-//        table.getSelectionModel().removeListSelectionListener(selectionRestorer);
-//      }
-//    }
-//
-//    /**
-//     * Updates the remembered selection. Calls {@link #storeSelection()}.
-//     */
-//    public void update() {
-//      storeSelection();
-//    }
-//    
-//    /**
-//     * Stores the current selection (according to the model)
-//     * in {@link #selectedModelRows}.
-//     */
-//    protected void storeSelection() {
-//      selectedModelRows = table.getSelectedRows();
-//      for (int i=0; i < selectedModelRows.length; i++)
-//        selectedModelRows[i] = table.convertRowIndexToModel(selectedModelRows[i]);
-//    }
-//    
-//    /**
-//     * Restores the remembered selection.
-//     */
-//    protected void restoreSelection() {
-//      if ( selectedModelRows == null )
-//        return;
-//      
-//      for (int row : selectedModelRows) {
-//        int tableRow = table.convertRowIndexToView(row);
-//        table.addRowSelectionInterval(tableRow,tableRow);
-//      }
-//    }
-//    
-//    /**
-//     * On mouse click (without holding Strg/Shift) the selection was
-//     * cleared. So we restore the remembered selection.
-//     */
-//    @Override
-//    public void mousePressed(MouseEvent e) {
-//      int modelCol = table.convertColumnIndexToModel(
-//                        table.columnAtPoint(e.getPoint()) );
-//      if ( modelCol == 0 )
-//        restoreSelection();
-//    }
-//    
-//    /**
-//     * After every click, remember the currently selected rows
-//     * according to the model.
-//     */
-//    @Override
-//    public void mouseReleased(MouseEvent e) {
-//      storeSelection();
-//    }
-//
-//    /**
-//     * After every key stroke, remember the currently selected rows
-//     * according to the model.
-//     */
-//    @Override
-//    public void keyReleased(KeyEvent e) {
-//      storeSelection();
-//    }
-//
-//    /** Does nothing. */
-//    @Override
-//    public void keyPressed(KeyEvent e) {}
-//    
-//    /** Does nothing. */
-//    @Override
-//    public void keyTyped(KeyEvent e) {}
-//    
-//    /**
-//     * Does currently nothing.
-//     */
-//    @Override
-//    public void valueChanged(ListSelectionEvent e) {
-//    }
-//  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing.table;
+
+import javax.swing.JTable;
+import javax.swing.event.TableModelListener;
+import javax.swing.table.AbstractTableModel;
+import javax.swing.table.TableModel;
+
+import schmitzm.swing.SelectableJTable;
+
+/**
+ * This table model extends an other {@link TableModel} by inserting an
+ * additional column 0 which shows and controls the row selection.
+ * To realize this functionality it is necessary to connect this table model
+ * to an explicit {@link JTable}. Besides it is necessary that this table
+ * is a {@link SelectableJTable} to overcome the "normal" click behavior (clear
+ * selection when no Ctrl/Shift key is hold), when clicking the selection column. 
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ */
+public class SelectionTableModel extends AbstractTableModel implements PipedTableModel {
+
+  /** Holds the table which controls the selection. */
+  protected SelectableJTable table = null;
+  /** Holds the base data. */
+  protected TableModel model = null;
+//!! SOLVED BY USING SelectableJTable !!
+//  /** Used to realize the selection column. */
+//  protected SelectionRestorer selectionRestorer = null;
+  
+  
+  /**
+   * Creates a new table model
+   * @param model provides the data
+   * @param table used to determine the row selection 
+   */
+  public SelectionTableModel(TableModel model, SelectableJTable table) {
+    super();
+    this.model = model;
+    this.table = table;
+    table.getColumnModel().setColumnSelectionAllowed(false);
+    
+//!! SOLVED BY USING SelectableJTable !!
+//    // Goal: By selection column cells, rows should be selected individually,
+//    //       without holding Strg/Shift key.
+//    // Problem: Also on a click in the selection column, the selection
+//    //          is first cleared
+//    // Solution: After every key stroke and every mouse click, the current
+//    //           selection is remembered. On click on selection column
+//    //           (the selection is already cleared!) the selection is
+//    //           restored. After that the click (TableModel.setValue(..)) is
+//    //           progressed, which extends the selection.
+//    this.selectionRestorer = new SelectionRestorer(table);
+  }
+
+//!! SOLVED BY USING SelectableJTable !!
+//  /**
+//   * Forces a update of the {@link SelectionRestorer} to renew the
+//   * remembered selected cells.
+//   */
+//  public void updateSelectionRestorer() {
+//    if ( selectionRestorer != null )
+//      selectionRestorer.update();
+//  }
+  
+  /**
+   * Returns the original {@link TableModel}.
+   */
+  @Override
+  public TableModel getPipedModel() {
+    return model;
+  }
+  
+  /**
+   * Adds a listener to the list that's notified each time a change
+   * to the data model occurs.
+   */
+  @Override
+  public void addTableModelListener(TableModelListener listener) {
+    model.addTableModelListener(listener);
+  }
+  
+  /**
+   * Removes a listener from the list that's notified each time a change
+   * to the data model occurs.
+   */
+  @Override
+  public void removeTableModelListener(TableModelListener listener) {
+    model.removeTableModelListener(listener);
+  }
+
+  /**
+   * Returns the type of a column.
+   * @return {@code Boolean.class} for column 0
+   */
+  @Override
+  public Class<?> getColumnClass(int col) {
+    if ( col == 0 )
+      return Boolean.class;
+   return model.getColumnClass(col - 1); 
+  }
+  
+  /**
+   * Returns the type of a column.
+   * @return {@code Boolean.class} for column 0
+   */
+  @Override
+  public int getColumnCount() {
+   return model.getColumnCount() + 1; 
+  }
+  
+  /**
+   * Returns the name of a column.
+   * @return empty string for column 0
+   */
+  @Override
+  public String getColumnName(int col) {
+    if ( col == 0 )
+      return "";
+   return model.getColumnName(col - 1); 
+  }
+  
+  /**
+   * Returns the number of rows in the model.
+   */
+  @Override
+  public int getRowCount() {
+    return model.getRowCount();
+  }
+
+  /**
+   * Returns the value for a cell.
+   * @param row row index
+   * @param col column index
+   */
+  @Override
+  public Object getValueAt(int row, int col) {
+    if ( col == 0 )
+      return table.isRowSelected( table.convertRowIndexToView(row) );
+    return model.getValueAt(row, col - 1);
+  }
+  
+  /**
+   * Sets a value for a cell.
+   * @param value new cell value
+   * @param row row index
+   * @param col column index
+   */
+  @Override
+  public void setValueAt(Object value, int row, int col) {
+    if ( col == 0 ) {
+      if ( value instanceof Boolean ) {
+        boolean select   = ((Boolean)value).booleanValue();
+        int     tableRow = table.convertRowIndexToView(row);
+        if ( select )
+          table.addRowSelectionInterval(tableRow, tableRow);
+        else
+          table.removeRowSelectionInterval(tableRow, tableRow);
+      }
+    } else
+      model.setValueAt(value, row, col - 1);
+  }
+
+  /**
+   * Returns the value for a cell.
+   * @param row row index
+   * @param col column index
+   * @param {@code true} for column 0
+   */
+  @Override
+  public boolean isCellEditable(int row, int col) {
+    if ( col == 0 )
+      return true;
+    return model.isCellEditable(row, col - 1);
+  }
+
+// !!! BY USING SelectableJTable THIS PROCEDURE IS NOT NEEDED ANYMORE !!!  
+//  /**
+//   * This listener must be added as {@link MouseListener} and {@link KeyListener}.
+//   * It stored the current table selection (rows) on every mouse click and key
+//   * stroke. On mouse click on selection column 0, the remembered selection
+//   * is restored to avoid the selection clear.<br><br>
+//   * 
+//   * <b>Goal:</b> By selection column cells, rows should be selected individually,
+//   *              without holding Strg/Shift key.<br>
+//   * <b>Problem:</b> Also on a click in the selection column, the selection
+//   *                 is first cleared.<br>
+//   * <b>Solution:</b> After every key stroke and every mouse click, the current
+//   *                  selection is remembered. On click on selection column
+//   *                  (the selection is already cleared!) the selection is
+//   *                  restored. After that the click (TableModel.setValue(..)) is
+//   *                  progressed, which extends the selection.
+//   */
+//  private static class SelectionRestorer extends MouseAdapter implements KeyListener, ListSelectionListener {
+//    /** Holds the table the selection is remembered from. */
+//    protected JTable table = null;
+//    /** Holds the remembered rows according to the model. */
+//    protected int[] selectedModelRows = null;
+//
+//    /**
+//     * Created a new selection rememberer and adds the listener to
+//     * the {@link JTable}.
+//     * @param table a table
+//     */
+//    public SelectionRestorer(JTable table) {
+//      super();
+//      connect(table);
+//    }
+//
+//    /**
+//     * Connects the {@link SelectionRestorer} to a {@link JTable}
+//     * as {@link MouseListener}, {@link KeyListener} and {@link ListSelectionListener}.
+//     * @param table a table
+//     */
+//    protected void connect(JTable table) {
+//      this.table = table;
+//      // remove all previously connected SelectionRestorers
+//      disconnect();
+//      // add Listeners
+//      table.addMouseListener(this);
+//      table.addKeyListener(this);
+//      table.getSelectionModel().addListSelectionListener(this);
+//    }
+//    
+//    /**
+//     * Disconnects the {@link SelectionRestorer} from the {@link JTable}.
+//     */
+//    public void disconnect() {
+//      // remove all previously connected SelectionRestorers
+//      SelectionRestorer[] selRest = table.getListeners(SelectionRestorer.class);
+//      for (SelectionRestorer selectionRestorer : selRest) {
+//        table.removeMouseListener(selectionRestorer);
+//        table.removeKeyListener(selectionRestorer);
+//        table.getSelectionModel().removeListSelectionListener(selectionRestorer);
+//      }
+//    }
+//
+//    /**
+//     * Updates the remembered selection. Calls {@link #storeSelection()}.
+//     */
+//    public void update() {
+//      storeSelection();
+//    }
+//    
+//    /**
+//     * Stores the current selection (according to the model)
+//     * in {@link #selectedModelRows}.
+//     */
+//    protected void storeSelection() {
+//      selectedModelRows = table.getSelectedRows();
+//      for (int i=0; i < selectedModelRows.length; i++)
+//        selectedModelRows[i] = table.convertRowIndexToModel(selectedModelRows[i]);
+//    }
+//    
+//    /**
+//     * Restores the remembered selection.
+//     */
+//    protected void restoreSelection() {
+//      if ( selectedModelRows == null )
+//        return;
+//      
+//      for (int row : selectedModelRows) {
+//        int tableRow = table.convertRowIndexToView(row);
+//        table.addRowSelectionInterval(tableRow,tableRow);
+//      }
+//    }
+//    
+//    /**
+//     * On mouse click (without holding Strg/Shift) the selection was
+//     * cleared. So we restore the remembered selection.
+//     */
+//    @Override
+//    public void mousePressed(MouseEvent e) {
+//      int modelCol = table.convertColumnIndexToModel(
+//                        table.columnAtPoint(e.getPoint()) );
+//      if ( modelCol == 0 )
+//        restoreSelection();
+//    }
+//    
+//    /**
+//     * After every click, remember the currently selected rows
+//     * according to the model.
+//     */
+//    @Override
+//    public void mouseReleased(MouseEvent e) {
+//      storeSelection();
+//    }
+//
+//    /**
+//     * After every key stroke, remember the currently selected rows
+//     * according to the model.
+//     */
+//    @Override
+//    public void keyReleased(KeyEvent e) {
+//      storeSelection();
+//    }
+//
+//    /** Does nothing. */
+//    @Override
+//    public void keyPressed(KeyEvent e) {}
+//    
+//    /** Does nothing. */
+//    @Override
+//    public void keyTyped(KeyEvent e) {}
+//    
+//    /**
+//     * Does currently nothing.
+//     */
+//    @Override
+//    public void valueChanged(ListSelectionEvent e) {
+//    }
+//  }
+}

Modified: trunk/src/schmitzm/swing/table/TableComponentMouseListener.java
===================================================================
--- trunk/src/schmitzm/swing/table/TableComponentMouseListener.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/table/TableComponentMouseListener.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,16 +1,34 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing.table;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing.table;
-
 import java.awt.Component;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseListener;
@@ -18,86 +36,86 @@
 import javax.swing.JTable;
 import javax.swing.SwingUtilities;
 import javax.swing.table.TableColumnModel;
-
-/**
- * Dieser MouseListener schleust Maus-Ereignisse auf eine Tabellenzelle
- * an die darin dargestellten {@link Component}-Objekte (z.B. einen Button) durch.
- * Hierzu muss der {@link JTable} eine Instanz dieses Listeners hinzugefuegt werden.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class TableComponentMouseListener implements MouseListener {
-  private JTable table;
-
-  /**
-   * Erzeugt einen neuen Listener fuer eine Tabelle.
-   * @param table Tabelle fuer die die Maus-Ereignisse durchgeschleust werden
-   */
-  public TableComponentMouseListener(JTable table) {
-    this.table = table;
-  }
-
-  private void forwardEventToButton(MouseEvent e) {
-    TableColumnModel columnModel = table.getColumnModel();
-
-    // Feststellen, auf welche Zelle geklickt wurde
-    int column = columnModel.getColumnIndexAtX(e.getX());
-    int row    = e.getY() / table.getRowHeight();
-    if( row    >= table.getRowCount()    | row < 0 ||
-        column >= table.getColumnCount() || column < 0)
-      return;
-    Object value = table.getValueAt(row, column);
-
-    // nichts tun, wenn es sich nicht um eine Componente handelt
-    if(!(value instanceof Component))
-      return;
-    Component comp = (Component)value;
-
-    MouseEvent buttonEvent = (MouseEvent)SwingUtilities.convertMouseEvent(table, e, comp);
-    comp.dispatchEvent(buttonEvent);
-    // This is necessary so that when a button is pressed and released
-    // it gets rendered properly.  Otherwise, the button may still appear
-    // pressed down when it has been released.
-    table.repaint();
-  }
-
-  /**
-   * Leitet das MouseClicked-Ereignis an die {@link Component} weiter.
-   * @param e MouseEvent
-   */
-  public void mouseClicked(MouseEvent e) {
-    forwardEventToButton(e);
-  }
-
-  /**
-   * Leitet das MouseEntered-Ereignis an die {@link Component} weiter.
-   * @param e MouseEvent
-   */
-  public void mouseEntered(MouseEvent e) {
-    forwardEventToButton(e);
-  }
-
-  /**
-   * Leitet das MouseExited-Ereignis an die {@link Component} weiter.
-   * @param e MouseEvent
-   */
-  public void mouseExited(MouseEvent e) {
-    forwardEventToButton(e);
-  }
-
-  /**
-   * Leitet das MousePressed-Ereignis an die {@link Component} weiter.
-   * @param e MouseEvent
-   */
-  public void mousePressed(MouseEvent e) {
-    forwardEventToButton(e);
-  }
-
-  /**
-   * Leitet das MouseReleased-Ereignis an die {@link Component} weiter.
-   * @param e MouseEvent
-   */
-  public void mouseReleased(MouseEvent e) {
-    forwardEventToButton(e);
-  }
-}
+
+/**
+ * Dieser MouseListener schleust Maus-Ereignisse auf eine Tabellenzelle
+ * an die darin dargestellten {@link Component}-Objekte (z.B. einen Button) durch.
+ * Hierzu muss der {@link JTable} eine Instanz dieses Listeners hinzugefuegt werden.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class TableComponentMouseListener implements MouseListener {
+  private JTable table;
+
+  /**
+   * Erzeugt einen neuen Listener fuer eine Tabelle.
+   * @param table Tabelle fuer die die Maus-Ereignisse durchgeschleust werden
+   */
+  public TableComponentMouseListener(JTable table) {
+    this.table = table;
+  }
+
+  private void forwardEventToButton(MouseEvent e) {
+    TableColumnModel columnModel = table.getColumnModel();
+
+    // Feststellen, auf welche Zelle geklickt wurde
+    int column = columnModel.getColumnIndexAtX(e.getX());
+    int row    = e.getY() / table.getRowHeight();
+    if( row    >= table.getRowCount()    | row < 0 ||
+        column >= table.getColumnCount() || column < 0)
+      return;
+    Object value = table.getValueAt(row, column);
+
+    // nichts tun, wenn es sich nicht um eine Componente handelt
+    if(!(value instanceof Component))
+      return;
+    Component comp = (Component)value;
+
+    MouseEvent buttonEvent = (MouseEvent)SwingUtilities.convertMouseEvent(table, e, comp);
+    comp.dispatchEvent(buttonEvent);
+    // This is necessary so that when a button is pressed and released
+    // it gets rendered properly.  Otherwise, the button may still appear
+    // pressed down when it has been released.
+    table.repaint();
+  }
+
+  /**
+   * Leitet das MouseClicked-Ereignis an die {@link Component} weiter.
+   * @param e MouseEvent
+   */
+  public void mouseClicked(MouseEvent e) {
+    forwardEventToButton(e);
+  }
+
+  /**
+   * Leitet das MouseEntered-Ereignis an die {@link Component} weiter.
+   * @param e MouseEvent
+   */
+  public void mouseEntered(MouseEvent e) {
+    forwardEventToButton(e);
+  }
+
+  /**
+   * Leitet das MouseExited-Ereignis an die {@link Component} weiter.
+   * @param e MouseEvent
+   */
+  public void mouseExited(MouseEvent e) {
+    forwardEventToButton(e);
+  }
+
+  /**
+   * Leitet das MousePressed-Ereignis an die {@link Component} weiter.
+   * @param e MouseEvent
+   */
+  public void mousePressed(MouseEvent e) {
+    forwardEventToButton(e);
+  }
+
+  /**
+   * Leitet das MouseReleased-Ereignis an die {@link Component} weiter.
+   * @param e MouseEvent
+   */
+  public void mouseReleased(MouseEvent e) {
+    forwardEventToButton(e);
+  }
+}

Modified: trunk/src/schmitzm/swing/tree/ContentNode.java
===================================================================
--- trunk/src/schmitzm/swing/tree/ContentNode.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/tree/ContentNode.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,72 +1,90 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing.tree;
-
-/**
- * Diese Klasse stellt Knoten dar, ein Objekt beinhaltet. Sie ist als
- * Pondon zu {@link EmptyNode} entworfen, implementiert zur Zeit jedoch
- * nichts anderes, als darauf zu achen, dass das User-Objekt
- * nicht auf <code>null</code> gesetzt wird.
- */
-public class ContentNode extends EditableNode {
-  private String desc = null;
-
-  /**
-   * Erzeugt einen neuen Knoten.
-   * @exception java.lang.UnsupportedOperationException falls <code>null</code>
-   *            als UserObject angegeben wird
-   */
-  public ContentNode(Object userObject, boolean editable) {
-    this(userObject, null, editable);
-  }
-
-  /**
-   * Erzeugt einen neuen Knoten.
-   * @exception java.lang.UnsupportedOperationException falls <code>null</code>
-   *            als UserObject angegeben wird
-   */
-  public ContentNode(Object userObject, String desc, boolean editable) {
-    super(userObject, editable);
-    this.desc = desc;
-    checkUserObject(userObject);
-  }
-
-  /**
-   * Setzt das User-Object neu.
-   * @exception java.lang.UnsupportedOperationException falls <code>null</code>
-   *            als UserObject angegeben wird
-   */
-  public void setUserObject(Object userObject) {
-    checkUserObject(userObject);
-    super.setUserObject(userObject);
-  }
-
-  /**
-   * Prueft ein Objekt auf <code>null</code>.
-   * @exception java.lang.UnsupportedOperationException falls <code>null</code>
-   *            als UserObject angegeben wird
-   */
-  private void checkUserObject(Object o) {
-    if (o==null)
-      throw new UnsupportedOperationException("ContentNode can not contain a null-UserObject!");
-  }
-
-  /**
-   * Liefert die Beschreibung, die fuer den Knoten angezeigt wird.
-   * Ist diese auf <code>null</code> gesetzt, wird die Standard-Bezeichnung
-   * <code>super.toString()</code> zurueckgegeben.
-   * @return String
-   */
-  public String toString() {
-    return desc != null ? desc : super.toString() ;
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing.tree;
+
+/**
+ * Diese Klasse stellt Knoten dar, ein Objekt beinhaltet. Sie ist als
+ * Pondon zu {@link EmptyNode} entworfen, implementiert zur Zeit jedoch
+ * nichts anderes, als darauf zu achen, dass das User-Objekt
+ * nicht auf <code>null</code> gesetzt wird.
+ */
+public class ContentNode extends EditableNode {
+  private String desc = null;
+
+  /**
+   * Erzeugt einen neuen Knoten.
+   * @exception java.lang.UnsupportedOperationException falls <code>null</code>
+   *            als UserObject angegeben wird
+   */
+  public ContentNode(Object userObject, boolean editable) {
+    this(userObject, null, editable);
+  }
+
+  /**
+   * Erzeugt einen neuen Knoten.
+   * @exception java.lang.UnsupportedOperationException falls <code>null</code>
+   *            als UserObject angegeben wird
+   */
+  public ContentNode(Object userObject, String desc, boolean editable) {
+    super(userObject, editable);
+    this.desc = desc;
+    checkUserObject(userObject);
+  }
+
+  /**
+   * Setzt das User-Object neu.
+   * @exception java.lang.UnsupportedOperationException falls <code>null</code>
+   *            als UserObject angegeben wird
+   */
+  public void setUserObject(Object userObject) {
+    checkUserObject(userObject);
+    super.setUserObject(userObject);
+  }
+
+  /**
+   * Prueft ein Objekt auf <code>null</code>.
+   * @exception java.lang.UnsupportedOperationException falls <code>null</code>
+   *            als UserObject angegeben wird
+   */
+  private void checkUserObject(Object o) {
+    if (o==null)
+      throw new UnsupportedOperationException("ContentNode can not contain a null-UserObject!");
+  }
+
+  /**
+   * Liefert die Beschreibung, die fuer den Knoten angezeigt wird.
+   * Ist diese auf <code>null</code> gesetzt, wird die Standard-Bezeichnung
+   * <code>super.toString()</code> zurueckgegeben.
+   * @return String
+   */
+  public String toString() {
+    return desc != null ? desc : super.toString() ;
+  }
+}

Modified: trunk/src/schmitzm/swing/tree/EditableNode.java
===================================================================
--- trunk/src/schmitzm/swing/tree/EditableNode.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/tree/EditableNode.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,59 +1,77 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing.tree;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+import javax.swing.tree.DefaultMutableTreeNode;
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+/**
+ * Diese Klasse erweitert den {@link javax.swing.tree.DefaultMutableTreeNode} um
+ * eine Editierbar?-Eigenschaft.
+ */
+public class EditableNode extends DefaultMutableTreeNode {
+  private boolean editable = false;
+  /**
+   * Erzeugt einen neuen Knoten. Diesem ist kein
+   * Inhalt zugeordnet, er kann aber Kindknoten erhalten.
+   */
+  public EditableNode(boolean editable) {
+    this(null, editable);
+  }
 
-package schmitzm.swing.tree;
-
-import javax.swing.tree.DefaultMutableTreeNode;
-
-/**
- * Diese Klasse erweitert den {@link javax.swing.tree.DefaultMutableTreeNode} um
- * eine Editierbar?-Eigenschaft.
- */
-public class EditableNode extends DefaultMutableTreeNode {
-  private boolean editable = false;
-  /**
-   * Erzeugt einen neuen Knoten. Diesem ist kein
-   * Inhalt zugeordnet, er kann aber Kindknoten erhalten.
-   */
-  public EditableNode(boolean editable) {
-    this(null, editable);
-  }
-
-  /**
-   * Erzeugt einen neuen Knoten. Diesem ist ein
-   * Inhalt zugeordnet und er kann Kindknoten erhalten.
-   */
-  public EditableNode(Object userObject, boolean editable) {
-    this(userObject, editable, true);
-  }
-
-  /**
-   * Erzeugt einen neuen Knoten. Diesem ist ein Inhalt zugeordnet.
-   * Ob er Kindknoten erhalten kann haengt vom
-   * <code>allowsChildren</code>-Parameter ab.
-   */
-  public EditableNode(Object userObject, boolean editable, boolean allowsChildren) {
-    super(userObject, allowsChildren);
-    this.editable = editable;
-  }
-
-  /**
-   * Prueft, ob der Knoten editierbar ist.
-   */
-  public boolean isEditable() {
-    return this.editable;
-  }
-}
-
-
-
-
-
+  /**
+   * Erzeugt einen neuen Knoten. Diesem ist ein
+   * Inhalt zugeordnet und er kann Kindknoten erhalten.
+   */
+  public EditableNode(Object userObject, boolean editable) {
+    this(userObject, editable, true);
+  }
+
+  /**
+   * Erzeugt einen neuen Knoten. Diesem ist ein Inhalt zugeordnet.
+   * Ob er Kindknoten erhalten kann haengt vom
+   * <code>allowsChildren</code>-Parameter ab.
+   */
+  public EditableNode(Object userObject, boolean editable, boolean allowsChildren) {
+    super(userObject, allowsChildren);
+    this.editable = editable;
+  }
+
+  /**
+   * Prueft, ob der Knoten editierbar ist.
+   */
+  public boolean isEditable() {
+    return this.editable;
+  }
+}
+
+
+
+
+

Modified: trunk/src/schmitzm/swing/tree/EmptyInnerNode.java
===================================================================
--- trunk/src/schmitzm/swing/tree/EmptyInnerNode.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/tree/EmptyInnerNode.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,93 +1,111 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing.tree;
 
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
+import javax.swing.tree.MutableTreeNode;
 
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
+/**
+ * Diese Klasse stellt einen inneren Knoten dar, der selbst kein Objekt
+ * beinhaltet, fuer den jedoch potentielle Kinder vorgesehen sind.
+ * Enthaelt er keine "richtigen" Kinder, erhaelt er einen Pseudo-Nachfolger
+ * "<leer>".
+ */
+public class EmptyInnerNode extends EmptyNode {
+  private final EmptyNode DUMMY_CHILD = new EmptyNode("<leer>");
+  /**
+   * Erzeugt einen neuen inneren Knoten.
+   * @param desc Beschreibung
+   */
+  public EmptyInnerNode(String desc) {
+    super(desc);
+    addDummyChild();
+  }
 
-package schmitzm.swing.tree;
-
-import javax.swing.tree.MutableTreeNode;
-
-/**
- * Diese Klasse stellt einen inneren Knoten dar, der selbst kein Objekt
- * beinhaltet, fuer den jedoch potentielle Kinder vorgesehen sind.
- * Enthaelt er keine "richtigen" Kinder, erhaelt er einen Pseudo-Nachfolger
- * "<leer>".
- */
-public class EmptyInnerNode extends EmptyNode {
-  private final EmptyNode DUMMY_CHILD = new EmptyNode("<leer>");
-  /**
-   * Erzeugt einen neuen inneren Knoten.
-   * @param desc Beschreibung
-   */
-  public EmptyInnerNode(String desc) {
-    super(desc);
-    addDummyChild();
-  }
-
-  /**
-   * Fuegt den Pseudo-Nachfolger ein.
-   */
-  private void addDummyChild() {
-    super.add(DUMMY_CHILD);
-  }
-
-  /**
-   * Fuegt dem Knoten ein Kind hinzu. Der Pseudo-Nachfolger wird zuvor
-   * entfernt (sofern er vorhanden war).
-   */
-  public void add(MutableTreeNode newChild) {
-    if ( getChildCount()==1 && getFirstChild()==DUMMY_CHILD )
-      super.remove(0);
-    super.add(newChild);
-  }
-
-  /**
-   * Entfernt ein Kind des Knotens. Falls es sich um den letzten Kindknoten
-   * handelt, wird der Pseudo-Nachfolger hinzugefuegt. Der Pseude-Nachfolger
-   * selbst kann nicht entfernt werden.
-   */
-  public void remove(MutableTreeNode aChild) {
-    // Pseudo-Nachfolger kann nicht entfernt werden
-    if ( aChild==DUMMY_CHILD )
-      return;
-    super.remove(aChild);
-    if ( getChildCount() == 0 )
-      addDummyChild();
-  }
-
-  /**
-   * Entfernt ein Kind des Knotens. Falls es sich um den letzten Kindknoten
-   * handelt, wird der Pseudo-Nachfolger hinzugefuegt. Der Pseude-Nachfolger
-   * selbst kann nicht entfernt werden.
-   */
-  public void remove(int index) {
-    // Pseudo-Nachfolger kann nicht entfernt werden
-    if (getChildAt(index) == DUMMY_CHILD)
-      return;
-    super.remove(index);
-    // Wenn der entfernte Knoten der letzte war, wird wieder ein
-    // Pseudo-Nachfolger hinzugefuegt
-    if ( getChildCount() == 0 )
-      addDummyChild();
-  }
-
-  /**
-   * Entfernt alle Kinder des Knotens und fuegt dann den Pseude-Nachfolger
-   * wieder hinzu.
-   */
-  public void removeAllChildren() {
-    super.removeAllChildren();
-    // Dummy wird nur hinzugefuegt, wenn die super-Methode ihn
-    // nicht bereits hinzugefuegt hat (das waere der Fall, wenn
-    // die super-Methode sukzessive eine andere remove-Methode
-    // aufruft.
-    if ( getChildCount() == 0 )
-      addDummyChild();
-  }
-}
+  /**
+   * Fuegt den Pseudo-Nachfolger ein.
+   */
+  private void addDummyChild() {
+    super.add(DUMMY_CHILD);
+  }
+
+  /**
+   * Fuegt dem Knoten ein Kind hinzu. Der Pseudo-Nachfolger wird zuvor
+   * entfernt (sofern er vorhanden war).
+   */
+  public void add(MutableTreeNode newChild) {
+    if ( getChildCount()==1 && getFirstChild()==DUMMY_CHILD )
+      super.remove(0);
+    super.add(newChild);
+  }
+
+  /**
+   * Entfernt ein Kind des Knotens. Falls es sich um den letzten Kindknoten
+   * handelt, wird der Pseudo-Nachfolger hinzugefuegt. Der Pseude-Nachfolger
+   * selbst kann nicht entfernt werden.
+   */
+  public void remove(MutableTreeNode aChild) {
+    // Pseudo-Nachfolger kann nicht entfernt werden
+    if ( aChild==DUMMY_CHILD )
+      return;
+    super.remove(aChild);
+    if ( getChildCount() == 0 )
+      addDummyChild();
+  }
+
+  /**
+   * Entfernt ein Kind des Knotens. Falls es sich um den letzten Kindknoten
+   * handelt, wird der Pseudo-Nachfolger hinzugefuegt. Der Pseude-Nachfolger
+   * selbst kann nicht entfernt werden.
+   */
+  public void remove(int index) {
+    // Pseudo-Nachfolger kann nicht entfernt werden
+    if (getChildAt(index) == DUMMY_CHILD)
+      return;
+    super.remove(index);
+    // Wenn der entfernte Knoten der letzte war, wird wieder ein
+    // Pseudo-Nachfolger hinzugefuegt
+    if ( getChildCount() == 0 )
+      addDummyChild();
+  }
+
+  /**
+   * Entfernt alle Kinder des Knotens und fuegt dann den Pseude-Nachfolger
+   * wieder hinzu.
+   */
+  public void removeAllChildren() {
+    super.removeAllChildren();
+    // Dummy wird nur hinzugefuegt, wenn die super-Methode ihn
+    // nicht bereits hinzugefuegt hat (das waere der Fall, wenn
+    // die super-Methode sukzessive eine andere remove-Methode
+    // aufruft.
+    if ( getChildCount() == 0 )
+      addDummyChild();
+  }
+}

Modified: trunk/src/schmitzm/swing/tree/EmptyNode.java
===================================================================
--- trunk/src/schmitzm/swing/tree/EmptyNode.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/swing/tree/EmptyNode.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,52 +1,70 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.swing.tree;
-
-/**
- * Diese Klasse stellt einen Knoten dar, der kein Objekt beinhaltet
- * (sondern nur eine Beschriftung). Er kann deshalb auch nicht
- * editiert werden.
- */
-public class EmptyNode extends EditableNode {
-  private String desc = "";
-
-  /**
-   * Erzeugt einen neuen leeren Knoten.
-   */
-  public EmptyNode() {
-    this("<empty>");
-  }
-
-  /**
-   * Erzeugt einen neuen leeren Knoten.
-   * @param desc Beschreibung fuer den Knoten
-   */
-  public EmptyNode(String desc) {
-    super(false);
-    this.desc = desc;
-  }
-
-  /**
-   * Liefert die Beschreibung des Knotens
-   * (anstelle von <code>getUserObject().toString()</code>).
-   */
-  public String toString() {
-    return desc;
-  }
-
-  /**
-   * Macht nichts, da der Knoten nicht editierbar ist!
-   * Ueberschreibt (sicherheitshalber) die Methode der Oberklasse.
-   */
-  public void setUserObject(Object object) {
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.swing.tree;
+
+/**
+ * Diese Klasse stellt einen Knoten dar, der kein Objekt beinhaltet
+ * (sondern nur eine Beschriftung). Er kann deshalb auch nicht
+ * editiert werden.
+ */
+public class EmptyNode extends EditableNode {
+  private String desc = "";
+
+  /**
+   * Erzeugt einen neuen leeren Knoten.
+   */
+  public EmptyNode() {
+    this("<empty>");
+  }
+
+  /**
+   * Erzeugt einen neuen leeren Knoten.
+   * @param desc Beschreibung fuer den Knoten
+   */
+  public EmptyNode(String desc) {
+    super(false);
+    this.desc = desc;
+  }
+
+  /**
+   * Liefert die Beschreibung des Knotens
+   * (anstelle von <code>getUserObject().toString()</code>).
+   */
+  public String toString() {
+    return desc;
+  }
+
+  /**
+   * Macht nichts, da der Knoten nicht editierbar ist!
+   * Ueberschreibt (sicherheitshalber) die Methode der Oberklasse.
+   */
+  public void setUserObject(Object object) {
+  }
+}

Modified: trunk/src/schmitzm/temp/BaseTypeUtil.java
===================================================================
--- trunk/src/schmitzm/temp/BaseTypeUtil.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/temp/BaseTypeUtil.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,445 +1,463 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package schmitzm.temp;
-
-// nur fuer Doku
-import schmitzm.data.property.Properties;
-
-/**
- * Diese Klasse stellt statische Methoden zur Arbeit mit BaseTypes bereit.
- * Mit BaseTypes sind folgende Klassen und Build-In-Types gemeint:
- * <table align=center border=2 cellpadding=5><code>
- * <tr><th>Klasse</th><th>entsprechender Build-In-Type</th></tr>
- * <tr><td><code>java.lang.Byte</code></td><td><code>byte.class</code></td></tr>
- * <tr><td><code>java.lang.Short</code></td><td><code>short.class</code></td></tr>
- * <tr><td><code>java.lang.Integer</code></td><td><code>int.class</code></td></tr>
- * <tr><td><code>java.lang.Long</code></td><td><code>long.class</code></td></tr>
- * <tr><td><code>java.lang.Float</code></td><td><code>float.class</code></td></tr>
- * <tr><td><code>java.lang.Double</code></td><td><code>double.class</code></td></tr>
- * <tr><td><code>java.lang.Boolean</code></td><td><code>boolen.class</code></td></tr>
- * <tr><td><code>java.lang.Character</code></td><td><code>char.class</code></td></tr>
- * <tr><td><code>java.lang.String</code></td><td>---</td></tr>
- * </table>
- * <br>
- * Seit JDK 1.5 koennen Build-In-Types auch als Objekte behandelt werden.
- * Diese Klasse stellt Methoden zur Kompatibilitaet zur Verfuegung.<br>
- * Die Methoden basieren jedoch sehr auf statischen Fallunterscheidungen!
- * Deshalb sollen sie nur als voruebergehende Notloesung dienen und zu
- * gegebener Zeit durch bessere (und u.U. effizientere Methoden) ersetzt werden.
- * <br><br>
- * Zur Zeit basieren folgende Methoden auf dieser Klasse:
- * <ul>
- * <li>{@link schmitzm.data.property.PropertyType#isValid(Class)}<br>
- *     Check: Eine BaseType-Objekt ist auch gueltig fuer eine Build-in-Property</li>
- * <li>{@link schmitzm.data.property.ValuePropertyType#isValid(Class)}<br>
- *     Check: Um welche Art von BaseType handelt es sich</li>
- * <li>{@link schmitzm.dipl.xulu.plugin.gui.DisplayContainer_Properties.PropertiesTableModel#isCellEditable(int,int)}<br>
- *     Check auf BaseType (nur diese Zellen sind editierbar).</li>
- * <li>{@link schmitzm.dipl.xulu.plugin.gui.DisplayContainer_Properties.PropertiesTableModel#setValueAt(Object,int,int)}<br>
- *     Umwandlung von String in Basistyp.</li>
- * <li>{@link schmitzm.dipl.xulu.plugin.io.misc.DynamicXuluObjectFactory_BasicStructure#createProperty()}<br>
- *     Umwandlung von String in Basistyp.</li>
- * <li>{@link schmitzm.dipl.xulu.plugin.model.TestModel.ContentManager}<br>
- *     Pruefen, ob Property einen numerischen Integer/Long beinhaltet.</li>
- * <li>{@link schmitzm.dipl.test.NumericMinMaxConstraint#isSatisfiedFor(Properties)}<br>
- *     Pruefen, ob Property einen numerischen Wert beinhaltet.</li>
- * </ul>
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class BaseTypeUtil {
-
-  /**
-   * Prueft, ob die angegebene Klasse einen Build-In-Type darstellt. Dies sind
-   * alle Typen, die oben in der rechten Spalte angegeben sind.
-   */
-  public static boolean isBuildInType(Class c) {
-    return c.equals(short.class) ||
-           c.equals(byte.class) ||
-           c.equals(int.class) ||
-           c.equals(long.class) ||
-           c.equals(float.class) ||
-           c.equals(double.class) ||
-           c.equals(char.class) ||
-           c.equals(boolean.class);
-  }
-
-  /**
-   * Prueft, ob das angegebene Objekt einen Build-In-Type darstellt. Dies sind
-   * alle Typen, die oben in der rechten Spalte angegeben sind.
-   * @return <code>false</code>, wenn das angegebene Objekt <code>null</code> ist
-   */
-  public static boolean isBuildInType(Object o) {
-    return o!=null && isBuildInType(o.getClass());
-  }
-
-
-  /**
-   * Prueft, ob die angegebene Klasse eine 8-bit-Ganzzahl darstellt.
-   * Also entweder <code>byte.class</code> oder <code>java.lang.Byte</code>.
-   */
-  public static boolean isByte(Class c) {
-    return c.equals(byte.class) || Byte.class.isAssignableFrom(c);
-  }
-
-  /**
-   * Prueft, ob das angegebene Objekt eine 8-bit-Ganzzahl darstellt.
-   * Also entweder eine Instanz von <code>byte.class</code> oder
-   * <code>java.lang.Byte</code> ist.
-   * @return <code>false</code>, wenn das angegebene Objekt <code>null</code> ist
-   */
-  public static boolean isByte(Object o) {
-    return o!=null && isByte(o.getClass());
-  }
-
-  /**
-   * Prueft, ob die angegebene Klasse eine 16-bit-Ganzzahl darstellt.
-   * Also entweder <code>short.class</code> oder <code>java.lang.Short</code>.
-   */
-  public static boolean isShort(Class c) {
-    return c.equals(short.class) || Short.class.isAssignableFrom(c);
-  }
-
-  /**
-   * Prueft, ob das angegebene Objekt eine 16-bit-Ganzzahl darstellt.
-   * Also entweder eine Instanz von <code>short.class</code> oder
-   * <code>java.lang.Short</code> ist.
-   * @return <code>false</code>, wenn das angegebene Objekt <code>null</code> ist
-   */
-  public static boolean isShort(Object o) {
-    return o!=null && isShort(o.getClass());
-  }
-
-  /**
-   * Prueft, ob die angegebene Klasse eine 32-bit-Ganzzahl darstellt.
-   * Also entweder <code>int.class</code> oder <code>java.lang.Integer</code>.
-   */
-  public static boolean isInteger(Class c) {
-    return c.equals(int.class) || Integer.class.isAssignableFrom(c);
-  }
-
-  /**
-   * Prueft, ob das angegebene Objekt eine 32-bit-Ganzzahl darstellt.
-   * Also entweder eine Instanz von <code>int.class</code> oder
-   * <code>java.lang.Integer</code> ist.
-   * @return <code>false</code>, wenn das angegebene Objekt <code>null</code> ist
-   */
-  public static boolean isInteger(Object o) {
-    return o!=null && isInteger(o.getClass());
-  }
-
-  /**
-   * Prueft, ob die angegebene Klasse eine 64-bit-Ganzzahl darstellt.
-   * Also entweder <code>long.class</code> oder <code>java.lang.Long</code>.
-   */
-  public static boolean isLong(Class c) {
-    return c.equals(long.class) || Long.class.isAssignableFrom(c);
-  }
-
-  /**
-   * Prueft, ob das angegebene Objekt eine 64-bit-Ganzzahl darstellt.
-   * Also entweder eine Instanz von <code>long.class</code> oder
-   * <code>java.lang.Long</code> ist.
-   * @return <code>false</code>, wenn das angegebene Objekt <code>null</code> ist
-   */
-  public static boolean isLong(Object o) {
-    return o!=null && isLong(o.getClass());
-  }
-
-  /**
-   * Prueft, ob die angegebene Klasse eine 32-bit-Gleitkommazahl darstellt.
-   * Also entweder <code>float.class</code> oder <code>java.lang.Float</code>.
-   */
-  public static boolean isFloat(Class c) {
-    return c.equals(float.class) || Float.class.isAssignableFrom(c);
-  }
-
-  /**
-   * Prueft, ob das angegebene Objekt eine 32-bit-Gleitkommazahl darstellt.
-   * Also entweder eine Instanz von <code>float.class</code> oder
-   * <code>java.lang.Float</code> ist.
-   * @return <code>false</code>, wenn das angegebene Objekt <code>null</code> ist
-   */
-  public static boolean isFloat(Object o) {
-    return o!=null && isFloat(o.getClass());
-  }
-
-  /**
-   * Prueft, ob die angegebene Klasse eine 64-bit-Gleitkommazahl darstellt.
-   * Also entweder <code>double.class</code> oder <code>java.lang.Couble</code>.
-   */
-  public static boolean isDouble(Class c) {
-    return c.equals(double.class) || Double.class.isAssignableFrom(c);
-  }
-
-  /**
-   * Prueft, ob das angegebene Objekt eine 64-bit-Gleitkommazahl darstellt.
-   * Also entweder eine Instanz von <code>double.class</code> oder
-   * <code>java.lang.Double</code> ist.
-   * @return <code>false</code>, wenn das angegebene Objekt <code>null</code> ist
-   */
-  public static boolean isDouble(Object o) {
-    return o!=null && isDouble(o.getClass());
-  }
-
-  /**
-   * Prueft, ob die angegebene Klasse einen boolschen Wert darstellt.
-   * Also entweder <code>boolean.class</code> oder <code>java.lang.Boolean</code>.
-   */
-  public static boolean isBoolean(Class c) {
-    return c.equals(boolean.class) || Boolean.class.isAssignableFrom(c);
-  }
-
-  /**
-   * Prueft, ob das angegebene Objekt einen boolschen Wert darstellt.
-   * Also entweder eine Instanz von <code>boolean.class</code> oder
-   * <code>java.lang.Boolean</code> ist.
-   * @return <code>false</code>, wenn das angegebene Objekt <code>null</code> ist
-   */
-  public static boolean isBoolean(Object o) {
-    return o!=null && isBoolean(o.getClass());
-  }
-
-  /**
-   * Prueft, ob die angegebene Klasse ein Zeichen darstellt.
-   * Also entweder <code>char.class</code> oder <code>java.lang.Character</code>.
-   */
-  public static boolean isCharacter(Class c) {
-    return c.equals(char.class) || Character.class.isAssignableFrom(c);
-  }
-
-  /**
-   * Prueft, ob das angegebene Objekt ein Zeichen darstellt.
-   * Also entweder eine Instanz von <code>char.class</code> oder
-   * <code>java.lang.Character</code> ist.
-   * @return <code>false</code>, wenn das angegebene Objekt <code>null</code> ist
-   */
-  public static boolean isCharacter(Object o) {
-    return o!=null && isCharacter(o.getClass());
-  }
-
-  /**
-   * Prueft, ob die angegebene Klasse eine Zeichenkette darstellt.
-   * Also <code>java.lang.String</code>.
-   */
-  public static boolean isString(Class c) {
-    return String.class.isAssignableFrom(c);
-  }
-
-  /**
-   * Prueft, ob das angegebene Objekt eine Zeichenkette darstellt.
-   * Also eine Instanz von <code>java.lang.String</code> ist.
-   * @return <code>false</code>, wenn das angegebene Objekt <code>null</code> ist
-   */
-  public static boolean isString(Object o) {
-    return o!=null && isString(o.getClass());
-  }
-
-  /**
-   * Prueft, ob die angegebene Klasse einen Basistyp (inkl. String) oder
-   * eine korrespondierende Klasse (z.B. <code>java.lang.Integer</code>) darstellt.
-   */
-  public static boolean isBaseType(Class c) {
-    return isByte(c) || isShort(c) || isInteger(c) || isLong(c) || isFloat(c) ||
-           isDouble(c) || isCharacter(c) || isString(c) || isBoolean(c);
-  }
-
-  /**
-   * Prueft, ob das angegebene Objekt einen Basistyp (auch String) oder
-   * eine korrespondierende Klasse (z.B. <code>java.lang.Integer</code>) darstellt.
-   */
-  public static boolean isBaseType(Object o) {
-    return o!=null && isBaseType(o.getClass());
-  }
-
-  /**
-   * Prueft, ob die angegebene Klasse einen numerischen Basistyp oder
-   * eine korrespondierende Klasse (z.B. <code>java.lang.Integer</code>) darstellt.
-   */
-  public static boolean isNumeric(Class c) {
-    return isByte(c) || isShort(c) || isInteger(c) || isLong(c) || isFloat(c) ||
-           isDouble(c);
-  }
-
-  /**
-   * Prueft, ob das angegebene Objekt einen numerischen Basistyp oder
-   * eine korrespondierende Klasse (z.B. <code>java.lang.Integer</code>) darstellt.
-   */
-  public static boolean isNumeric(Object o) {
-    return o!=null && isNumeric(o.getClass());
-  }
-
-  /**
-   * Prueft, ob die angegebene Klasse eine Dezimalzahl oder
-   * eine korrespondierende Klasse (z.B. <code>java.lang.Double</code>) darstellt.
-   */
-  public static boolean isDecimal(Class c) {
-    return isFloat(c) || isDouble(c);
-  }
-
-  /**
-   * Prueft, ob das angegebene Objekt eine Dezimalzahl oder
-   * eine korrespondierende Klasse (z.B. <code>java.lang.Double</code>) darstellt.
-   */
-  public static boolean isDecimal(Object o) {
-    return o!=null && isDecimal(o.getClass());
-  }
-
-  /**
-   * Prueft, ob zwei BaseType-Klassen zueinander kompatibel sind
-   * @return <code>false</code> wenn eine der Klassen <b>keinen</b> BaseType
-   *         darstellt
-   */
-  public static boolean isEquivalent(Class c1, Class c2) {
-    return isByte(c1) && isByte(c2) ||
-           isShort(c1) && isShort(c2) ||
-           isInteger(c1) && isInteger(c2) ||
-           isLong(c1) && isLong(c2) ||
-           isFloat(c1) && isFloat(c2) ||
-           isDouble(c1) && isDouble(c2) ||
-           isBoolean(c1) && isBoolean(c2) ||
-           isCharacter(c1) && isCharacter(c2) ||
-           isString(c1) && isString(c2) ||
-           isBoolean(c1) && isBoolean(c2);
-  }
-
-  /**
-   * Prueft, ob zwei BaseType-Objekte zueinander kompatibel sind
-   * @return <code>false</code> wenn eines der Objekte <b>keinen</b> BaseType
-   *         darstellt oder <code>null</code> ist
-   */
-  public static boolean isEquivalent(Object o1, Object o2) {
-    return o1!=null && o2!=null && isEquivalent(o1.getClass(),o2.getClass());
-  }
-
-  /**
-   * Prueft, ob eine numerische Datentyp-Klasse in eine andere numerische
-   * Datentyp-Klasse (ohne Verlust) umgewandelt werden kann.
-   * @param fromClass Ausgangs-Datentyp
-   * @param to Class  Ziel-Datentyp
-   */
-  public static boolean isConvertable(Class<Number> fromClass, Class<Number> toClass) {
-    // gleiche Typen koennen immer ineinander umgewandelt werden
-    if ( fromClass.equals( toClass ) )
-      return true;
-
-    // Float kann in Double umgewandelt werden
-    if ( Float.class.equals(fromClass) )
-      return Double.class.equals(toClass);
-
-    // Integer kann in Long umgewandelt werden
-    if ( Integer.class.equals(fromClass) )
-      return Long.class.equals(toClass);
-
-    // Byte kann in Long und Integer umgewandelt werden
-    if ( Byte.class.equals(fromClass) )
-      return Integer.class.equals(toClass)
-          || Long.class.equals(toClass) ;
-
-    // Short kann in Long und Integer umgewandelt werden
-    if ( Short.class.equals(fromClass) )
-      return Integer.class.equals(toClass)
-          || Long.class.equals(toClass) ;
-
-    return false;
-  }
-
-  /**
-   * Wandelt einen numerischen Wert in einen bestimmten Datentyp um.
-   * Dabei kann
-   * @param source   numerisches Datenobjekt
-   * @param destType Typ, in den das Objekt umgewandelt wird
-   */
-  public static Object convertNumber(Number source, Class<Number> destType) {
-    if ( Double.class.equals(destType) )
-      return source.doubleValue();
-    if ( Float.class.equals(destType) )
-      return source.floatValue();
-    if ( Long.class.equals(destType) )
-      return source.longValue();
-    if ( Integer.class.equals(destType) )
-      return source.intValue();
-    if ( Byte.class.equals(destType) )
-      return source.byteValue();
-    if ( Short.class.equals(destType) )
-      return source.shortValue();
-    throw new UnsupportedClassVersionError("Unsupported numeric type: "+(destType != null ? destType.getSimpleName() : "null"));
-  }
-
-  /**
-   * Erzeugt eine BaseType-Instanz aus einem String.
-   * @param strValue Zeichenkette, die das Objekt darstellt
-   * @param destType BaseType in den konvertiert werden soll
-   */
-  public static <T> T convertFromString(String strValue, Class<? extends T> destType) {
-    if (!isBaseType(destType))
-      return null;
-
-    // Beim String ist nicht zu machen
-    if ( isString(destType) )
-      return (T)strValue;
-
-    // Bei allen anderen Typen wird ein Leerstring zu null
-    if ( strValue == null || strValue.equals("") )
-      return null;
-
-    // Bei Zeichen, wird das erste vom String genommen
-    if ( isCharacter(destType) )
-      return (T)new Character(strValue.charAt(0));
-    // Bei Zahlen oder Boolean wird versucht aus dem
-    // String zu parsen
-    if ( isShort(destType) )
-      return (T)new Short(strValue);
-    if ( isByte(destType) )
-      return (T)new Byte(strValue);
-    if ( isInteger(destType) )
-      return (T)new Integer(strValue);
-    if ( isLong(destType) )
-      return (T)new Long(strValue);
-    if ( isFloat(destType) )
-      return (T)new Float(strValue);
-    if ( isDouble(destType) )
-      return (T)new Double(strValue);
-    if ( isBoolean(destType) )
-      return (T)new Boolean(strValue);
-
-    return null;
-  }
-
-  /**
-   * Erzeugt eine BaseType-Instanz aus einem String. Es wird versucht, einen
-   * der folgenden Datentypen zu erzeugen:
-   * <ol>
-   * <li><code>Integer</code></li>
-   * <li><code>Double</code></li>
-   * <li><code>String</code></li>
-   * </ol>
-   * @param strValue Zeichenkette, die das Objekt darstellt
-   */
-  public static Object convertFromString(String strValue) {
-    // erst versuchen einen Integer zu erzeugen
-    try {
-      return Integer.parseInt(strValue);
-    } catch (NumberFormatException err) {
-    }
-
-    // dann versuchen einen Double zu erzeugen
-    try {
-      return Double.parseDouble(strValue);
-    } catch (NumberFormatException err) {
-    }
-
-    // sonst beim String belassen
-    return strValue;
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.temp;
+
+// nur fuer Doku
+import schmitzm.data.property.Properties;
+
+/**
+ * Diese Klasse stellt statische Methoden zur Arbeit mit BaseTypes bereit.
+ * Mit BaseTypes sind folgende Klassen und Build-In-Types gemeint:
+ * <table align=center border=2 cellpadding=5><code>
+ * <tr><th>Klasse</th><th>entsprechender Build-In-Type</th></tr>
+ * <tr><td><code>java.lang.Byte</code></td><td><code>byte.class</code></td></tr>
+ * <tr><td><code>java.lang.Short</code></td><td><code>short.class</code></td></tr>
+ * <tr><td><code>java.lang.Integer</code></td><td><code>int.class</code></td></tr>
+ * <tr><td><code>java.lang.Long</code></td><td><code>long.class</code></td></tr>
+ * <tr><td><code>java.lang.Float</code></td><td><code>float.class</code></td></tr>
+ * <tr><td><code>java.lang.Double</code></td><td><code>double.class</code></td></tr>
+ * <tr><td><code>java.lang.Boolean</code></td><td><code>boolen.class</code></td></tr>
+ * <tr><td><code>java.lang.Character</code></td><td><code>char.class</code></td></tr>
+ * <tr><td><code>java.lang.String</code></td><td>---</td></tr>
+ * </table>
+ * <br>
+ * Seit JDK 1.5 koennen Build-In-Types auch als Objekte behandelt werden.
+ * Diese Klasse stellt Methoden zur Kompatibilitaet zur Verfuegung.<br>
+ * Die Methoden basieren jedoch sehr auf statischen Fallunterscheidungen!
+ * Deshalb sollen sie nur als voruebergehende Notloesung dienen und zu
+ * gegebener Zeit durch bessere (und u.U. effizientere Methoden) ersetzt werden.
+ * <br><br>
+ * Zur Zeit basieren folgende Methoden auf dieser Klasse:
+ * <ul>
+ * <li>{@link schmitzm.data.property.PropertyType#isValid(Class)}<br>
+ *     Check: Eine BaseType-Objekt ist auch gueltig fuer eine Build-in-Property</li>
+ * <li>{@link schmitzm.data.property.ValuePropertyType#isValid(Class)}<br>
+ *     Check: Um welche Art von BaseType handelt es sich</li>
+ * <li>{@link schmitzm.dipl.xulu.plugin.gui.DisplayContainer_Properties.PropertiesTableModel#isCellEditable(int,int)}<br>
+ *     Check auf BaseType (nur diese Zellen sind editierbar).</li>
+ * <li>{@link schmitzm.dipl.xulu.plugin.gui.DisplayContainer_Properties.PropertiesTableModel#setValueAt(Object,int,int)}<br>
+ *     Umwandlung von String in Basistyp.</li>
+ * <li>{@link schmitzm.dipl.xulu.plugin.io.misc.DynamicXuluObjectFactory_BasicStructure#createProperty()}<br>
+ *     Umwandlung von String in Basistyp.</li>
+ * <li>{@link schmitzm.dipl.xulu.plugin.model.TestModel.ContentManager}<br>
+ *     Pruefen, ob Property einen numerischen Integer/Long beinhaltet.</li>
+ * <li>{@link schmitzm.dipl.test.NumericMinMaxConstraint#isSatisfiedFor(Properties)}<br>
+ *     Pruefen, ob Property einen numerischen Wert beinhaltet.</li>
+ * </ul>
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class BaseTypeUtil {
+
+  /**
+   * Prueft, ob die angegebene Klasse einen Build-In-Type darstellt. Dies sind
+   * alle Typen, die oben in der rechten Spalte angegeben sind.
+   */
+  public static boolean isBuildInType(Class c) {
+    return c.equals(short.class) ||
+           c.equals(byte.class) ||
+           c.equals(int.class) ||
+           c.equals(long.class) ||
+           c.equals(float.class) ||
+           c.equals(double.class) ||
+           c.equals(char.class) ||
+           c.equals(boolean.class);
+  }
+
+  /**
+   * Prueft, ob das angegebene Objekt einen Build-In-Type darstellt. Dies sind
+   * alle Typen, die oben in der rechten Spalte angegeben sind.
+   * @return <code>false</code>, wenn das angegebene Objekt <code>null</code> ist
+   */
+  public static boolean isBuildInType(Object o) {
+    return o!=null && isBuildInType(o.getClass());
+  }
+
+
+  /**
+   * Prueft, ob die angegebene Klasse eine 8-bit-Ganzzahl darstellt.
+   * Also entweder <code>byte.class</code> oder <code>java.lang.Byte</code>.
+   */
+  public static boolean isByte(Class c) {
+    return c.equals(byte.class) || Byte.class.isAssignableFrom(c);
+  }
+
+  /**
+   * Prueft, ob das angegebene Objekt eine 8-bit-Ganzzahl darstellt.
+   * Also entweder eine Instanz von <code>byte.class</code> oder
+   * <code>java.lang.Byte</code> ist.
+   * @return <code>false</code>, wenn das angegebene Objekt <code>null</code> ist
+   */
+  public static boolean isByte(Object o) {
+    return o!=null && isByte(o.getClass());
+  }
+
+  /**
+   * Prueft, ob die angegebene Klasse eine 16-bit-Ganzzahl darstellt.
+   * Also entweder <code>short.class</code> oder <code>java.lang.Short</code>.
+   */
+  public static boolean isShort(Class c) {
+    return c.equals(short.class) || Short.class.isAssignableFrom(c);
+  }
+
+  /**
+   * Prueft, ob das angegebene Objekt eine 16-bit-Ganzzahl darstellt.
+   * Also entweder eine Instanz von <code>short.class</code> oder
+   * <code>java.lang.Short</code> ist.
+   * @return <code>false</code>, wenn das angegebene Objekt <code>null</code> ist
+   */
+  public static boolean isShort(Object o) {
+    return o!=null && isShort(o.getClass());
+  }
+
+  /**
+   * Prueft, ob die angegebene Klasse eine 32-bit-Ganzzahl darstellt.
+   * Also entweder <code>int.class</code> oder <code>java.lang.Integer</code>.
+   */
+  public static boolean isInteger(Class c) {
+    return c.equals(int.class) || Integer.class.isAssignableFrom(c);
+  }
+
+  /**
+   * Prueft, ob das angegebene Objekt eine 32-bit-Ganzzahl darstellt.
+   * Also entweder eine Instanz von <code>int.class</code> oder
+   * <code>java.lang.Integer</code> ist.
+   * @return <code>false</code>, wenn das angegebene Objekt <code>null</code> ist
+   */
+  public static boolean isInteger(Object o) {
+    return o!=null && isInteger(o.getClass());
+  }
+
+  /**
+   * Prueft, ob die angegebene Klasse eine 64-bit-Ganzzahl darstellt.
+   * Also entweder <code>long.class</code> oder <code>java.lang.Long</code>.
+   */
+  public static boolean isLong(Class c) {
+    return c.equals(long.class) || Long.class.isAssignableFrom(c);
+  }
+
+  /**
+   * Prueft, ob das angegebene Objekt eine 64-bit-Ganzzahl darstellt.
+   * Also entweder eine Instanz von <code>long.class</code> oder
+   * <code>java.lang.Long</code> ist.
+   * @return <code>false</code>, wenn das angegebene Objekt <code>null</code> ist
+   */
+  public static boolean isLong(Object o) {
+    return o!=null && isLong(o.getClass());
+  }
+
+  /**
+   * Prueft, ob die angegebene Klasse eine 32-bit-Gleitkommazahl darstellt.
+   * Also entweder <code>float.class</code> oder <code>java.lang.Float</code>.
+   */
+  public static boolean isFloat(Class c) {
+    return c.equals(float.class) || Float.class.isAssignableFrom(c);
+  }
+
+  /**
+   * Prueft, ob das angegebene Objekt eine 32-bit-Gleitkommazahl darstellt.
+   * Also entweder eine Instanz von <code>float.class</code> oder
+   * <code>java.lang.Float</code> ist.
+   * @return <code>false</code>, wenn das angegebene Objekt <code>null</code> ist
+   */
+  public static boolean isFloat(Object o) {
+    return o!=null && isFloat(o.getClass());
+  }
+
+  /**
+   * Prueft, ob die angegebene Klasse eine 64-bit-Gleitkommazahl darstellt.
+   * Also entweder <code>double.class</code> oder <code>java.lang.Couble</code>.
+   */
+  public static boolean isDouble(Class c) {
+    return c.equals(double.class) || Double.class.isAssignableFrom(c);
+  }
+
+  /**
+   * Prueft, ob das angegebene Objekt eine 64-bit-Gleitkommazahl darstellt.
+   * Also entweder eine Instanz von <code>double.class</code> oder
+   * <code>java.lang.Double</code> ist.
+   * @return <code>false</code>, wenn das angegebene Objekt <code>null</code> ist
+   */
+  public static boolean isDouble(Object o) {
+    return o!=null && isDouble(o.getClass());
+  }
+
+  /**
+   * Prueft, ob die angegebene Klasse einen boolschen Wert darstellt.
+   * Also entweder <code>boolean.class</code> oder <code>java.lang.Boolean</code>.
+   */
+  public static boolean isBoolean(Class c) {
+    return c.equals(boolean.class) || Boolean.class.isAssignableFrom(c);
+  }
+
+  /**
+   * Prueft, ob das angegebene Objekt einen boolschen Wert darstellt.
+   * Also entweder eine Instanz von <code>boolean.class</code> oder
+   * <code>java.lang.Boolean</code> ist.
+   * @return <code>false</code>, wenn das angegebene Objekt <code>null</code> ist
+   */
+  public static boolean isBoolean(Object o) {
+    return o!=null && isBoolean(o.getClass());
+  }
+
+  /**
+   * Prueft, ob die angegebene Klasse ein Zeichen darstellt.
+   * Also entweder <code>char.class</code> oder <code>java.lang.Character</code>.
+   */
+  public static boolean isCharacter(Class c) {
+    return c.equals(char.class) || Character.class.isAssignableFrom(c);
+  }
+
+  /**
+   * Prueft, ob das angegebene Objekt ein Zeichen darstellt.
+   * Also entweder eine Instanz von <code>char.class</code> oder
+   * <code>java.lang.Character</code> ist.
+   * @return <code>false</code>, wenn das angegebene Objekt <code>null</code> ist
+   */
+  public static boolean isCharacter(Object o) {
+    return o!=null && isCharacter(o.getClass());
+  }
+
+  /**
+   * Prueft, ob die angegebene Klasse eine Zeichenkette darstellt.
+   * Also <code>java.lang.String</code>.
+   */
+  public static boolean isString(Class c) {
+    return String.class.isAssignableFrom(c);
+  }
+
+  /**
+   * Prueft, ob das angegebene Objekt eine Zeichenkette darstellt.
+   * Also eine Instanz von <code>java.lang.String</code> ist.
+   * @return <code>false</code>, wenn das angegebene Objekt <code>null</code> ist
+   */
+  public static boolean isString(Object o) {
+    return o!=null && isString(o.getClass());
+  }
+
+  /**
+   * Prueft, ob die angegebene Klasse einen Basistyp (inkl. String) oder
+   * eine korrespondierende Klasse (z.B. <code>java.lang.Integer</code>) darstellt.
+   */
+  public static boolean isBaseType(Class c) {
+    return isByte(c) || isShort(c) || isInteger(c) || isLong(c) || isFloat(c) ||
+           isDouble(c) || isCharacter(c) || isString(c) || isBoolean(c);
+  }
+
+  /**
+   * Prueft, ob das angegebene Objekt einen Basistyp (auch String) oder
+   * eine korrespondierende Klasse (z.B. <code>java.lang.Integer</code>) darstellt.
+   */
+  public static boolean isBaseType(Object o) {
+    return o!=null && isBaseType(o.getClass());
+  }
+
+  /**
+   * Prueft, ob die angegebene Klasse einen numerischen Basistyp oder
+   * eine korrespondierende Klasse (z.B. <code>java.lang.Integer</code>) darstellt.
+   */
+  public static boolean isNumeric(Class c) {
+    return isByte(c) || isShort(c) || isInteger(c) || isLong(c) || isFloat(c) ||
+           isDouble(c);
+  }
+
+  /**
+   * Prueft, ob das angegebene Objekt einen numerischen Basistyp oder
+   * eine korrespondierende Klasse (z.B. <code>java.lang.Integer</code>) darstellt.
+   */
+  public static boolean isNumeric(Object o) {
+    return o!=null && isNumeric(o.getClass());
+  }
+
+  /**
+   * Prueft, ob die angegebene Klasse eine Dezimalzahl oder
+   * eine korrespondierende Klasse (z.B. <code>java.lang.Double</code>) darstellt.
+   */
+  public static boolean isDecimal(Class c) {
+    return isFloat(c) || isDouble(c);
+  }
+
+  /**
+   * Prueft, ob das angegebene Objekt eine Dezimalzahl oder
+   * eine korrespondierende Klasse (z.B. <code>java.lang.Double</code>) darstellt.
+   */
+  public static boolean isDecimal(Object o) {
+    return o!=null && isDecimal(o.getClass());
+  }
+
+  /**
+   * Prueft, ob zwei BaseType-Klassen zueinander kompatibel sind
+   * @return <code>false</code> wenn eine der Klassen <b>keinen</b> BaseType
+   *         darstellt
+   */
+  public static boolean isEquivalent(Class c1, Class c2) {
+    return isByte(c1) && isByte(c2) ||
+           isShort(c1) && isShort(c2) ||
+           isInteger(c1) && isInteger(c2) ||
+           isLong(c1) && isLong(c2) ||
+           isFloat(c1) && isFloat(c2) ||
+           isDouble(c1) && isDouble(c2) ||
+           isBoolean(c1) && isBoolean(c2) ||
+           isCharacter(c1) && isCharacter(c2) ||
+           isString(c1) && isString(c2) ||
+           isBoolean(c1) && isBoolean(c2);
+  }
+
+  /**
+   * Prueft, ob zwei BaseType-Objekte zueinander kompatibel sind
+   * @return <code>false</code> wenn eines der Objekte <b>keinen</b> BaseType
+   *         darstellt oder <code>null</code> ist
+   */
+  public static boolean isEquivalent(Object o1, Object o2) {
+    return o1!=null && o2!=null && isEquivalent(o1.getClass(),o2.getClass());
+  }
+
+  /**
+   * Prueft, ob eine numerische Datentyp-Klasse in eine andere numerische
+   * Datentyp-Klasse (ohne Verlust) umgewandelt werden kann.
+   * @param fromClass Ausgangs-Datentyp
+   * @param to Class  Ziel-Datentyp
+   */
+  public static boolean isConvertable(Class<Number> fromClass, Class<Number> toClass) {
+    // gleiche Typen koennen immer ineinander umgewandelt werden
+    if ( fromClass.equals( toClass ) )
+      return true;
+
+    // Float kann in Double umgewandelt werden
+    if ( Float.class.equals(fromClass) )
+      return Double.class.equals(toClass);
+
+    // Integer kann in Long umgewandelt werden
+    if ( Integer.class.equals(fromClass) )
+      return Long.class.equals(toClass);
+
+    // Byte kann in Long und Integer umgewandelt werden
+    if ( Byte.class.equals(fromClass) )
+      return Integer.class.equals(toClass)
+          || Long.class.equals(toClass) ;
+
+    // Short kann in Long und Integer umgewandelt werden
+    if ( Short.class.equals(fromClass) )
+      return Integer.class.equals(toClass)
+          || Long.class.equals(toClass) ;
+
+    return false;
+  }
+
+  /**
+   * Wandelt einen numerischen Wert in einen bestimmten Datentyp um.
+   * Dabei kann
+   * @param source   numerisches Datenobjekt
+   * @param destType Typ, in den das Objekt umgewandelt wird
+   */
+  public static Object convertNumber(Number source, Class<Number> destType) {
+    if ( Double.class.equals(destType) )
+      return source.doubleValue();
+    if ( Float.class.equals(destType) )
+      return source.floatValue();
+    if ( Long.class.equals(destType) )
+      return source.longValue();
+    if ( Integer.class.equals(destType) )
+      return source.intValue();
+    if ( Byte.class.equals(destType) )
+      return source.byteValue();
+    if ( Short.class.equals(destType) )
+      return source.shortValue();
+    throw new UnsupportedClassVersionError("Unsupported numeric type: "+(destType != null ? destType.getSimpleName() : "null"));
+  }
+
+  /**
+   * Erzeugt eine BaseType-Instanz aus einem String.
+   * @param strValue Zeichenkette, die das Objekt darstellt
+   * @param destType BaseType in den konvertiert werden soll
+   */
+  public static <T> T convertFromString(String strValue, Class<? extends T> destType) {
+    if (!isBaseType(destType))
+      return null;
+
+    // Beim String ist nicht zu machen
+    if ( isString(destType) )
+      return (T)strValue;
+
+    // Bei allen anderen Typen wird ein Leerstring zu null
+    if ( strValue == null || strValue.equals("") )
+      return null;
+
+    // Bei Zeichen, wird das erste vom String genommen
+    if ( isCharacter(destType) )
+      return (T)new Character(strValue.charAt(0));
+    // Bei Zahlen oder Boolean wird versucht aus dem
+    // String zu parsen
+    if ( isShort(destType) )
+      return (T)new Short(strValue);
+    if ( isByte(destType) )
+      return (T)new Byte(strValue);
+    if ( isInteger(destType) )
+      return (T)new Integer(strValue);
+    if ( isLong(destType) )
+      return (T)new Long(strValue);
+    if ( isFloat(destType) )
+      return (T)new Float(strValue);
+    if ( isDouble(destType) )
+      return (T)new Double(strValue);
+    if ( isBoolean(destType) )
+      return (T)new Boolean(strValue);
+
+    return null;
+  }
+
+  /**
+   * Erzeugt eine BaseType-Instanz aus einem String. Es wird versucht, einen
+   * der folgenden Datentypen zu erzeugen:
+   * <ol>
+   * <li><code>Integer</code></li>
+   * <li><code>Double</code></li>
+   * <li><code>String</code></li>
+   * </ol>
+   * @param strValue Zeichenkette, die das Objekt darstellt
+   */
+  public static Object convertFromString(String strValue) {
+    // erst versuchen einen Integer zu erzeugen
+    try {
+      return Integer.parseInt(strValue);
+    } catch (NumberFormatException err) {
+    }
+
+    // dann versuchen einen Double zu erzeugen
+    try {
+      return Double.parseDouble(strValue);
+    } catch (NumberFormatException err) {
+    }
+
+    // sonst beim String belassen
+    return strValue;
+  }
+
+}

Modified: trunk/src/schmitzm/xml/XMLUtil.java
===================================================================
--- trunk/src/schmitzm/xml/XMLUtil.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/schmitzm/xml/XMLUtil.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,186 +1,215 @@
-package schmitzm.xml;
-
-import java.awt.Color;
-
-import org.apache.log4j.Logger;
-import org.jdom.Element;
-import org.jdom.adapters.JAXPDOMAdapter;
-import org.jdom.output.XMLOutputter;
-
-import schmitzm.swing.SwingUtil;
-
-
-/**
- * Diese Klasse enthaelt statische Helper-Methoden fuer das Arbeiten mit XML.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class XMLUtil {
-  /** Logger, to give debug and warning messaged. */
-  private static Logger LOGGER = Logger.getLogger( XMLUtil.class.getName() );
-
-  /** Wrapper from JDOM to W3C. */
-  public static final JAXPDOMAdapter JDOM_TO_JAX = new JAXPDOMAdapter();
-  /** Writes XML element to file. */
-  public static final XMLOutputter XML_OUTPUTTER = new XMLOutputter();
-
-  /**
-   * Gets the attribute value from element.
-   * @param element  element where the attribute is determined from
-   * @param attrName name of the attribute
-   * @param defValue default value returned if attribute is not found (or empty)
-   * @return {@code null} if {@code element} is {@code null} or attribute is not
-   *         specified in element
-   */
-  public static String getAttribute(Element element, String attrName, String... defValue) {
-    if ( element == null )
-      return null;
-    String attrValue = element.getAttributeValue(attrName);
-    if ( (attrValue == null || "".equals(attrValue)) && defValue.length >= 1 )
-      return defValue[0];
-    return attrValue;
-  }
-
-  /**
-   * Gets the attribute value from element as {@link Boolean}.
-   * @param element  element where the attribute is determined from
-   * @param attrName name of the attribute
-   * @param defValue optional default value returned if attribute is not found (or empty)
-   * @return {@code null} if {@code element} is {@code null} or attribute is not
-   *         specified in element
-   */
-  public static Boolean getBooleanAttribute(Element element, String attrName, Boolean... defValue) {
-    String value = getAttribute(element, attrName);
-    if ( value != null )
-      return Boolean.parseBoolean(value);
-    if ( defValue.length > 0 )
-      return defValue[0];
-    return null;
-  }
-  
-  /**
-   * Gets the attribute value from element as {@link Integer}.
-   * @param element  element where the attribute is determined from
-   * @param attrName name of the attribute
-   * @param defValue optional default value returned if attribute is not found (or empty)
-   * @return {@code null} if {@code element} is {@code null} or attribute is not
-   *         specified in element
-   */
-  public static Integer getIntegerAttribute(Element element, String attrName, Integer... defValue) {
-    String value = getAttribute(element, attrName);
-    if ( value != null )
-      return Integer.parseInt(value);
-    if ( defValue.length > 0 )
-      return defValue[0];
-    return null;
-  }
-
-  /**
-   * Gets the attribute value from element as {@link Double}.
-   * @param element  element where the attribute is determined from
-   * @param attrName name of the attribute
-   * @param defValue optional default value returned if attribute is not found (or empty)
-   * @return {@code null} if {@code element} is {@code null} or attribute is not
-   *         specified in element
-   */
-  public static Double getDoubleAttribute(Element element, String attrName, Double... defValue) {
-    String value = getAttribute(element, attrName);
-    if ( value != null )
-      return Double.parseDouble(value);
-    if ( defValue.length > 0 )
-      return defValue[0];
-    return null;
-  }
-
-  /**
-   * Gets the attribute value from element as {@link Float}.
-   * @param element  element where the attribute is determined from
-   * @param attrName name of the attribute
-   * @param defValue optional default value returned if attribute is not found (or empty)
-   * @return {@code null} if {@code element} is {@code null} or attribute is not
-   *         specified in element
-   */
-  public static Float getFloatAttribute(Element element, String attrName, Float... defValue) {
-    String value = getAttribute(element, attrName);
-    if ( value != null )
-      return Float.parseFloat(value);
-    if ( defValue.length > 0 )
-      return defValue[0];
-    return null;
-  }
-
-  /**
-   * Gets the attribute value from element as {@link Color}.
-   * @param element  element where the attribute is determined from
-   * @param attrName name of the attribute
-   * @param defValue optional default value returned if attribute is not found (or empty)
-   * @return {@code null} if {@code element} is {@code null} or attribute is not
-   *         specified in element
-   */
-  public static Color getColorAttribute(Element element, String attrName, Color... defValue) {
-    String value = getAttribute(element, attrName);
-    if ( value != null )
-      return SwingUtil.parseColor(value);
-    if ( defValue.length > 0 )
-      return defValue[0];
-    return null;
-  }
-  //  /**
-//   * Returns a {@link DocumentBuilder}. If validating is true,
-//   * the contents is validated against the XSD specified in the file.
-//   */
-//  private final static DocumentBuilder getDocumentBuilder(final boolean validating) throws SAXException, IOException, ParserConfigurationException {
-//    // Create a builder factory
-//    final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
-//
-//    factory.setNamespaceAware(true);
-//    final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
-//    final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
-//    factory.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
-////    factory.setValidating(validating);
-//
-//    // Create the builder and parse the file
-//    final DocumentBuilder documentBuilder = factory.newDocumentBuilder();
-////    documentBuilder.setErrorHandler(new ErrorHandler() {
-////      public void error(final SAXParseException exception) throws SAXException {
-////        LOGGER.error("ErrorHandler.error");
-////        throw exception;
-////      }
-////      public void fatalError(final SAXParseException exception) throws SAXException {
-////        LOGGER.error("ErrorHandler.fataError");
-////        throw exception;
-////      }
-////      public void warning(final SAXParseException exception) throws SAXException {
-////        LOGGER.warn("ErrorHandler.warning", exception);
-////      }
-////    });
-////
-//    return documentBuilder;
-//  }
-
-//  /**
-//   * Wraps a {@linkplain Element JDOM-Element} to a {@linkplain Node W3C-Node}.
-//   * @param element a JDOM-Element
-//   */
-//  public static Node wrapElement(Element element) {
-////    String  xmlDefinition = new XMLOutputter().outputString( new Document(element,element.getDocument().getDocType()) );
-////    Document document = new DefaultJDOMFactory().document( element );
-//    String  xmlString = new XMLOutputter().outputString( element );
-//
-//    try {
-//      InputStream xmlStream = new ByteArrayInputStream(xmlString.getBytes());
-//      DocumentBuilder builder = getDocumentBuilder(false);
-//      org.w3c.dom.Document node = builder.parse(xmlStream);
-//
-////      org.w3c.dom.Document node = JDOM_TO_JAX.getDocument(xmlStream,true);
-//
-//      LOGGER.debug( xmlString );
-//      LOGGER.debug( node.hasAttributes() );
-//      xmlStream.close();
-//      return node;
-//    } catch ( Exception err ) {
-//      throw new UnsupportedOperationException("Error during XML wrapping", err);
-//    }
-//  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package schmitzm.xml;
+
+import java.awt.Color;
+
+import org.apache.log4j.Logger;
+import org.jdom.Element;
+import org.jdom.adapters.JAXPDOMAdapter;
+import org.jdom.output.XMLOutputter;
+
+import schmitzm.swing.SwingUtil;
+
+
+/**
+ * Diese Klasse enthaelt statische Helper-Methoden fuer das Arbeiten mit XML.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class XMLUtil {
+  /** Logger, to give debug and warning messaged. */
+  private static Logger LOGGER = Logger.getLogger( XMLUtil.class.getName() );
+
+  /** Wrapper from JDOM to W3C. */
+  public static final JAXPDOMAdapter JDOM_TO_JAX = new JAXPDOMAdapter();
+  /** Writes XML element to file. */
+  public static final XMLOutputter XML_OUTPUTTER = new XMLOutputter();
+
+  /**
+   * Gets the attribute value from element.
+   * @param element  element where the attribute is determined from
+   * @param attrName name of the attribute
+   * @param defValue default value returned if attribute is not found (or empty)
+   * @return {@code null} if {@code element} is {@code null} or attribute is not
+   *         specified in element
+   */
+  public static String getAttribute(Element element, String attrName, String... defValue) {
+    if ( element == null )
+      return null;
+    String attrValue = element.getAttributeValue(attrName);
+    if ( (attrValue == null || "".equals(attrValue)) && defValue.length >= 1 )
+      return defValue[0];
+    return attrValue;
+  }
+
+  /**
+   * Gets the attribute value from element as {@link Boolean}.
+   * @param element  element where the attribute is determined from
+   * @param attrName name of the attribute
+   * @param defValue optional default value returned if attribute is not found (or empty)
+   * @return {@code null} if {@code element} is {@code null} or attribute is not
+   *         specified in element
+   */
+  public static Boolean getBooleanAttribute(Element element, String attrName, Boolean... defValue) {
+    String value = getAttribute(element, attrName);
+    if ( value != null )
+      return Boolean.parseBoolean(value);
+    if ( defValue.length > 0 )
+      return defValue[0];
+    return null;
+  }
+  
+  /**
+   * Gets the attribute value from element as {@link Integer}.
+   * @param element  element where the attribute is determined from
+   * @param attrName name of the attribute
+   * @param defValue optional default value returned if attribute is not found (or empty)
+   * @return {@code null} if {@code element} is {@code null} or attribute is not
+   *         specified in element
+   */
+  public static Integer getIntegerAttribute(Element element, String attrName, Integer... defValue) {
+    String value = getAttribute(element, attrName);
+    if ( value != null )
+      return Integer.parseInt(value);
+    if ( defValue.length > 0 )
+      return defValue[0];
+    return null;
+  }
+
+  /**
+   * Gets the attribute value from element as {@link Double}.
+   * @param element  element where the attribute is determined from
+   * @param attrName name of the attribute
+   * @param defValue optional default value returned if attribute is not found (or empty)
+   * @return {@code null} if {@code element} is {@code null} or attribute is not
+   *         specified in element
+   */
+  public static Double getDoubleAttribute(Element element, String attrName, Double... defValue) {
+    String value = getAttribute(element, attrName);
+    if ( value != null )
+      return Double.parseDouble(value);
+    if ( defValue.length > 0 )
+      return defValue[0];
+    return null;
+  }
+
+  /**
+   * Gets the attribute value from element as {@link Float}.
+   * @param element  element where the attribute is determined from
+   * @param attrName name of the attribute
+   * @param defValue optional default value returned if attribute is not found (or empty)
+   * @return {@code null} if {@code element} is {@code null} or attribute is not
+   *         specified in element
+   */
+  public static Float getFloatAttribute(Element element, String attrName, Float... defValue) {
+    String value = getAttribute(element, attrName);
+    if ( value != null )
+      return Float.parseFloat(value);
+    if ( defValue.length > 0 )
+      return defValue[0];
+    return null;
+  }
+
+  /**
+   * Gets the attribute value from element as {@link Color}.
+   * @param element  element where the attribute is determined from
+   * @param attrName name of the attribute
+   * @param defValue optional default value returned if attribute is not found (or empty)
+   * @return {@code null} if {@code element} is {@code null} or attribute is not
+   *         specified in element
+   */
+  public static Color getColorAttribute(Element element, String attrName, Color... defValue) {
+    String value = getAttribute(element, attrName);
+    if ( value != null )
+      return SwingUtil.parseColor(value);
+    if ( defValue.length > 0 )
+      return defValue[0];
+    return null;
+  }
+  //  /**
+//   * Returns a {@link DocumentBuilder}. If validating is true,
+//   * the contents is validated against the XSD specified in the file.
+//   */
+//  private final static DocumentBuilder getDocumentBuilder(final boolean validating) throws SAXException, IOException, ParserConfigurationException {
+//    // Create a builder factory
+//    final DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
+//
+//    factory.setNamespaceAware(true);
+//    final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage";
+//    final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema";
+//    factory.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA);
+////    factory.setValidating(validating);
+//
+//    // Create the builder and parse the file
+//    final DocumentBuilder documentBuilder = factory.newDocumentBuilder();
+////    documentBuilder.setErrorHandler(new ErrorHandler() {
+////      public void error(final SAXParseException exception) throws SAXException {
+////        LOGGER.error("ErrorHandler.error");
+////        throw exception;
+////      }
+////      public void fatalError(final SAXParseException exception) throws SAXException {
+////        LOGGER.error("ErrorHandler.fataError");
+////        throw exception;
+////      }
+////      public void warning(final SAXParseException exception) throws SAXException {
+////        LOGGER.warn("ErrorHandler.warning", exception);
+////      }
+////    });
+////
+//    return documentBuilder;
+//  }
+
+//  /**
+//   * Wraps a {@linkplain Element JDOM-Element} to a {@linkplain Node W3C-Node}.
+//   * @param element a JDOM-Element
+//   */
+//  public static Node wrapElement(Element element) {
+////    String  xmlDefinition = new XMLOutputter().outputString( new Document(element,element.getDocument().getDocType()) );
+////    Document document = new DefaultJDOMFactory().document( element );
+//    String  xmlString = new XMLOutputter().outputString( element );
+//
+//    try {
+//      InputStream xmlStream = new ByteArrayInputStream(xmlString.getBytes());
+//      DocumentBuilder builder = getDocumentBuilder(false);
+//      org.w3c.dom.Document node = builder.parse(xmlStream);
+//
+////      org.w3c.dom.Document node = JDOM_TO_JAX.getDocument(xmlStream,true);
+//
+//      LOGGER.debug( xmlString );
+//      LOGGER.debug( node.hasAttributes() );
+//      xmlStream.close();
+//      return node;
+//    } catch ( Exception err ) {
+//      throw new UnsupportedOperationException("Error during XML wrapping", err);
+//    }
+//  }
+
+}

Modified: trunk/src/skrueger/AttributeMetaData.java
===================================================================
--- trunk/src/skrueger/AttributeMetaData.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/AttributeMetaData.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,88 +1,117 @@
-package skrueger;
-
-import org.apache.log4j.Logger;
-
-import skrueger.geotools.StyledLayerInterface;
-import skrueger.i8n.Translation;
-
-/**
- * This class holds meta information about an attribute/column. This
- * information is used by {@link StyledLayerInterface}.
- *
- * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
- */
-public class AttributeMetaData {
-	static private final Logger LOGGER = Logger
-			.getLogger(AttributeMetaData.class);
-	protected Translation title = new Translation();
-	protected Translation desc = new Translation();
-	protected boolean visible = false;
-	protected String unit = "";
-	protected int colIdx;
-
-	/**
-	 * Creates an {@link AttributeMetaData} object with the following information
-	 * @param colIdx The column index of this attribute in the underlying table/dbf/etc...
-	 * @param visible Shall this attribute be displayed or hidden from the user?
-	 * @param title {@link Translation} for Name
-	 * @param desc {@link Translation} for an attribute description
-	 * @param unit {@link String} of the unit that the information is in
-	 */
-	public AttributeMetaData(final int colIdx, final Boolean visible,
-			final Translation title, final Translation desc, final String unit) {
-	
-		this.colIdx = colIdx;
-		this.title = title;
-		this.desc = desc;
-		if (colIdx == 0){
-			// The first attribut is THE_GEOM and shall never be visible!
-			this.visible = false;
-		}else
-			this.visible = visible;
-		this.unit = unit;
-	}
-
-	/**
-	 * Creates a new visible {@link AttributeMetaData} with default (no) values.  
-	 */
-	public AttributeMetaData(final Integer col, final String defaultName) {
-		this(col, true, new Translation(defaultName), new Translation(), "");
-	}
-
-	public Boolean isVisible() {
-		return visible;
-	}
-
-	public void setVisible(final Boolean visible) {
-		this.visible = visible;
-	}
-
-	/** @return the index of this attribute in the underlying table/dbf **/
-	public int getColIdx() {
-		return colIdx;
-	}
-
-	public Translation getTitle() {
-		return title;
-	}
-
-	public void setTitle(final Translation title) {
-		this.title = title;
-	}
-
-	public Translation getDesc() {
-		return desc;
-	}
-
-	public void setDesc(final Translation desc) {
-		this.desc = desc;
-	}
-
-	public String getUnit() {
-		return unit;
-	}
-
-	public void setUnit(final String unit) {
-		this.unit = unit;
-	}
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package skrueger;
+
+import org.apache.log4j.Logger;
+
+import skrueger.geotools.StyledLayerInterface;
+import skrueger.i8n.Translation;
+
+/**
+ * This class holds meta information about an attribute/column. This
+ * information is used by {@link StyledLayerInterface}.
+ *
+ * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
+ */
+public class AttributeMetaData {
+	static private final Logger LOGGER = Logger
+			.getLogger(AttributeMetaData.class);
+	protected Translation title = new Translation();
+	protected Translation desc = new Translation();
+	protected boolean visible = false;
+	protected String unit = "";
+	protected int colIdx;
+
+	/**
+	 * Creates an {@link AttributeMetaData} object with the following information
+	 * @param colIdx The column index of this attribute in the underlying table/dbf/etc...
+	 * @param visible Shall this attribute be displayed or hidden from the user?
+	 * @param title {@link Translation} for Name
+	 * @param desc {@link Translation} for an attribute description
+	 * @param unit {@link String} of the unit that the information is in
+	 */
+	public AttributeMetaData(final int colIdx, final Boolean visible,
+			final Translation title, final Translation desc, final String unit) {
+	
+		this.colIdx = colIdx;
+		this.title = title;
+		this.desc = desc;
+		if (colIdx == 0){
+			// The first attribut is THE_GEOM and shall never be visible!
+			this.visible = false;
+		}else
+			this.visible = visible;
+		this.unit = unit;
+	}
+
+	/**
+	 * Creates a new visible {@link AttributeMetaData} with default (no) values.  
+	 */
+	public AttributeMetaData(final Integer col, final String defaultName) {
+		this(col, true, new Translation(defaultName), new Translation(), "");
+	}
+
+	public Boolean isVisible() {
+		return visible;
+	}
+
+	public void setVisible(final Boolean visible) {
+		this.visible = visible;
+	}
+
+	/** @return the index of this attribute in the underlying table/dbf **/
+	public int getColIdx() {
+		return colIdx;
+	}
+
+	public Translation getTitle() {
+		return title;
+	}
+
+	public void setTitle(final Translation title) {
+		this.title = title;
+	}
+
+	public Translation getDesc() {
+		return desc;
+	}
+
+	public void setDesc(final Translation desc) {
+		this.desc = desc;
+	}
+
+	public String getUnit() {
+		return unit;
+	}
+
+	public void setUnit(final String unit) {
+		this.unit = unit;
+	}
+}

Modified: trunk/src/skrueger/AttributeMetaDataAttributeTypeFilter.java
===================================================================
--- trunk/src/skrueger/AttributeMetaDataAttributeTypeFilter.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/AttributeMetaDataAttributeTypeFilter.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,58 +1,87 @@
-package skrueger;
-
-import java.util.HashMap;
-import java.util.Map;
-
-import org.geotools.feature.AttributeType;
-
-import schmitzm.geotools.feature.AttributeTypeFilter;
-
-/**
- * Implements an {@link AttributeTypeFilter} using the
- * {@linkplain AttributeMetaData#isVisible() visible}-property of an
- * {@link AttributeMetaData} map (or array).<br>
- * If this filter is created from a {@code null} map or {@code null} array,
- * the filter accepts ALL attributes except geometries.
- * @see AttributeTypeFilter#NO_GEOMETRY
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class AttributeMetaDataAttributeTypeFilter implements AttributeTypeFilter {
-
-  /** The meta data of a set of attributes */
-  protected Map<Integer,AttributeMetaData> attrMetaDataMap = null;
-
-  /**
-   * Creates a new filter.
-   * @param attrMetaData the meta data of some attributes
-   */
-  public AttributeMetaDataAttributeTypeFilter(AttributeMetaData[] attrMetaData) {
-    this.attrMetaDataMap = new HashMap<Integer,AttributeMetaData>();
-    for (int i=0; attrMetaData!=null && i<attrMetaData.length; i++)
-      this.attrMetaDataMap.put(i, attrMetaData[i]);
-  }
-
-  /**
-   * Creates a new filter.
-   * @param attrMetaData the meta data of some attributes
-   */
-  public AttributeMetaDataAttributeTypeFilter(Map<Integer,AttributeMetaData> attrMetaData) {
-    this.attrMetaDataMap = attrMetaData;
-  }
-
-  /**
-   * Returns {@code true} if the attribute meta data at index {@code idx} is
-   * visible and the attribute is no geometry at all.
-   */
-  public boolean accept(AttributeType type, int idx) {
-    // if no meta data is given, all attributes (except Geometry)
-    // are treaten as visible
-    if ( attrMetaDataMap == null )
-      return NO_GEOMETRY.accept(type, idx);
-
-    AttributeMetaData metaData = attrMetaDataMap.get(idx);
-    return NO_GEOMETRY.accept(type, idx)  // no geometry attributes at all
-        && metaData != null               // meta data must be present for column
-        && metaData.isVisible();          // attribute must be visible
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package skrueger;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.geotools.feature.AttributeType;
+
+import schmitzm.geotools.feature.AttributeTypeFilter;
+
+/**
+ * Implements an {@link AttributeTypeFilter} using the
+ * {@linkplain AttributeMetaData#isVisible() visible}-property of an
+ * {@link AttributeMetaData} map (or array).<br>
+ * If this filter is created from a {@code null} map or {@code null} array,
+ * the filter accepts ALL attributes except geometries.
+ * @see AttributeTypeFilter#NO_GEOMETRY
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class AttributeMetaDataAttributeTypeFilter implements AttributeTypeFilter {
+
+  /** The meta data of a set of attributes */
+  protected Map<Integer,AttributeMetaData> attrMetaDataMap = null;
+
+  /**
+   * Creates a new filter.
+   * @param attrMetaData the meta data of some attributes
+   */
+  public AttributeMetaDataAttributeTypeFilter(AttributeMetaData[] attrMetaData) {
+    this.attrMetaDataMap = new HashMap<Integer,AttributeMetaData>();
+    for (int i=0; attrMetaData!=null && i<attrMetaData.length; i++)
+      this.attrMetaDataMap.put(i, attrMetaData[i]);
+  }
+
+  /**
+   * Creates a new filter.
+   * @param attrMetaData the meta data of some attributes
+   */
+  public AttributeMetaDataAttributeTypeFilter(Map<Integer,AttributeMetaData> attrMetaData) {
+    this.attrMetaDataMap = attrMetaData;
+  }
+
+  /**
+   * Returns {@code true} if the attribute meta data at index {@code idx} is
+   * visible and the attribute is no geometry at all.
+   */
+  public boolean accept(AttributeType type, int idx) {
+    // if no meta data is given, all attributes (except Geometry)
+    // are treaten as visible
+    if ( attrMetaDataMap == null )
+      return NO_GEOMETRY.accept(type, idx);
+
+    AttributeMetaData metaData = attrMetaDataMap.get(idx);
+    return NO_GEOMETRY.accept(type, idx)  // no geometry attributes at all
+        && metaData != null               // meta data must be present for column
+        && metaData.isVisible();          // attribute must be visible
+  }
+}

Modified: trunk/src/skrueger/RasterLegendData.java
===================================================================
--- trunk/src/skrueger/RasterLegendData.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/RasterLegendData.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,56 +1,85 @@
-package skrueger;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.LinkedList;
-import java.util.List;
-
-import org.apache.log4j.Logger;
-
-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.
- *
- * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
- *
- */
-public class RasterLegendData extends HashMap<Double, Translation> {
-	static private final Logger LOGGER = Logger.getLogger(RasterLegendData.class);
-	private Boolean paintGaps = false;
-
-	public Boolean isPaintGaps() {
-		return paintGaps;
-	}
-
-	public void setPaintGaps(boolean paintPaps) {
-		this.paintGaps = paintPaps;
-	}
-
-	/**
-	 * {@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) {
-		super();
-		this.paintGaps = paintGaps;
-	}
-
-	public boolean getPaintGaps() {
-		return paintGaps ;
-	}
-
-	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);
-		}
-
-		return linkedList;
-
-	}
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package skrueger;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.log4j.Logger;
+
+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.
+ *
+ * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
+ *
+ */
+public class RasterLegendData extends HashMap<Double, Translation> {
+	static private final Logger LOGGER = Logger.getLogger(RasterLegendData.class);
+	private Boolean paintGaps = false;
+
+	public Boolean isPaintGaps() {
+		return paintGaps;
+	}
+
+	public void setPaintGaps(boolean paintPaps) {
+		this.paintGaps = paintPaps;
+	}
+
+	/**
+	 * {@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) {
+		super();
+		this.paintGaps = paintGaps;
+	}
+
+	public boolean getPaintGaps() {
+		return paintGaps ;
+	}
+
+	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);
+		}
+
+		return linkedList;
+
+	}
+}

Modified: trunk/src/skrueger/geotools/AbstractStyledLayer.java
===================================================================
--- trunk/src/skrueger/geotools/AbstractStyledLayer.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/AbstractStyledLayer.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,253 +1,282 @@
-package skrueger.geotools;
-
-import javax.swing.ImageIcon;
-
-import org.apache.log4j.Logger;
-import org.geotools.styling.Style;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-
-import schmitzm.lang.LangUtil;
-import skrueger.i8n.Translation;
-
-import com.vividsolutions.jts.geom.Envelope;
-
-/**
- * This class is a default implementation of {@link StyledLayerInterface}.
- * {@link StyledLayerInterface#dispose()} and {@link StyledLayerInterface#uncache()}
- * must be implemented by the sub class. This class only implements the "hold"
- * of an geo object of type {@code <E>}.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public abstract class AbstractStyledLayer<E> implements StyledLayerInterface<E> {
-  /** Logger for warning- and error messages. */
-  protected Logger LOGGER = LangUtil.createLogger(this);
-
-  /** Holds the unique ID of the geo object. */
-  protected String id = null;
-  /** Holds a short (language-specific) description of the geo object. */
-  protected Translation title = null;
-  /** Holds a long (language-specific) description of the geo object. */
-  protected Translation desc = null;
-  /** Holds the (language-specific) keywords to describe the geo object. */
-  protected Translation keywords = null;
-  /** Holds an icon to represent the geo object */
-  protected ImageIcon icon = null;
-  /** Holds the geo object represeneted by the map */
-  protected E geoObject = null;
-  /** Holds the CRS of the geo object */
-  protected CoordinateReferenceSystem crs = null;
-  /** Holds the bounds of the geo object */
-  protected Envelope envelope = null;
-  /** Holds the display style for the geo object */
-  protected Style style = null;
-
-  /**
-   * Creates a language specific styled layer.
-   * @param geoObject the geo object
-   * @param envelope the bounds of the geo object
-   * @param crs the CRS of the geo object
-   * @param id a unique ID for the geo object
-   * @param title a (language-specific) short description
-   * @param desc a (language-specific) long description
-   * @param keywords (language-specific) keywords for the geo objects
-   * @param style a display style
-   * @param icon an icon for the object
-   * @exception IllegalArgumentException if {@code null} is given as ID or
-   *            geo object
-   */
-  public AbstractStyledLayer(E geoObject, Envelope envelope, CoordinateReferenceSystem crs, String id, Translation title, Translation desc, Translation keywords, Style style, ImageIcon icon) {
-    if ( id == null )
-      throw new IllegalArgumentException("ID is not allowed to be null!");
-    if ( geoObject == null )
-      throw new IllegalArgumentException("The GeoObject is not allowed to be null!");
-    this.id        = id;
-    this.geoObject = geoObject;
-    this.crs       = crs;
-    this.envelope  = envelope;
-    setTitle( title );
-    setDesc( desc );
-    setKeywords( keywords );
-    setStyle( style );
-    setImageIcon( icon );
-  }
-
-  /**
-   * Creates a non-translated styled layer.
-   * @param geoObject the geo object
-   * @param envelope the bounds of the geo object
-   * @param crs the CRS of the geo object
-   * @param id a unique ID for the geo object
-   * @param title a short description
-   * @param desc a long description
-   * @param keywords keywords for the geo objects
-   * @param style a display style
-   * @param icon an icon for the object
-   * @exception IllegalArgumentException if {@code null} is given as ID
-   */
-  public AbstractStyledLayer(E geoObject, Envelope envelope, CoordinateReferenceSystem crs, String id, String title, String desc, String keywords, Style style, ImageIcon icon ) {
-    this(geoObject, envelope, crs, id, (Translation)null, null, null, style, icon);
-    setTitle( title );
-    setDesc( desc );
-    setKeywords( keywords );
-  }
-
-  /**
-   * Returns a ID for the geo object. The ID should be unique in a map ob
-   * {@linkplain StyledLayerInterface styled layer objects}
-   */
-  public String getId() {
-    return id;
-  }
-
-  /**
-   * Returns a short (language-specific) description of the geo object.
-   */
-  public Translation getTitle() {
-    return title;
-  }
-
-  /**
-   * Sets a short (language-specific) description of the geo object.
-   * If {@code title} is {@code null} an untranslated default title is set, so
-   * {@link #getTitle()} never returns {@code null}.
-   * @param title new description for the geo object
-   */
-  public void setTitle(Translation title) {
-    this.title = (title != null) ? title : new Translation("untitled");
-  }
-
-  /**
-   * Sets a short (non-translated) description of the geo object.
-   * If {@code title} is {@code null} an untranslated default title is set, so
-   * {@link #getTitle()} never returns {@code null}.
-   * @param title new description for the geo object
-   */
-  public void setTitle(String title) {
-    setTitle( title != null ? new Translation(title): (Translation)null );
-  }
-
-  /**
-   * Returns a long (language-specific) description of the object.
-   */
-  public Translation getDesc() {
-    return desc;
-  }
-
-  /**
-   * Sets a long (language-specific) description of the object.
-   * If {@code desc} is {@code null} an (untranslated) empty description is set, so
-   * {@link #getDesc()} never returns {@code null}.
-   * @param desc new description for the geo object
-  */
-  public void setDesc(Translation desc) {
-    this.desc = (desc != null) ? desc : new Translation("");
-  }
-
-  /**
-   * Sets a long (non-translated) description of the object.
-   * If {@code desc} is {@code null} an (untranslated) empty description is set, so
-   * {@link #getDesc()} never returns {@code null}.
-   * @param desc new description for the geo object
-  */
-  public void setDesc(String desc) {
-    setDesc( desc != null ? new Translation(desc) : (Translation)null);
-  }
-
-  /**
-   * Returns a (language-specific) key word sequence for the geo object.
-   */
-  public Translation getKeywords() {
-    return keywords;
-  }
-
-  /**
-   * Sets a (language-specific) key word sequence for the geo object.
-   * If {@code keywords} is {@code null} an (untranslated) empty string is set, so
-   * {@link #getKeywords()} never returns {@code null}.
-   * @param keywords Keywords
-   */
-  public void setKeywords(Translation keywords) {
-    this.keywords = (keywords != null) ? keywords : new Translation("");
-  }
-
-  /**
-   * Sets a (non-translated) key word sequence for the geo object.
-   * If {@code keywords} is {@code null} an (untranslated) empty string is set, so
-   * {@link #getKeywords()} never returns {@code null}.
-   * @param keywords Keywords
-   */
-  public void setKeywords(String keywords) {
-    setKeywords( keywords != null ? new Translation(keywords) : (Translation)null);
-  }
-
-  /**
-   * Returns the geo object representet in the map. Sub classes must override
-   * this method to implement "late loading" on first call.
-   * @return {@link #geoObject}
-   */
-  public E getGeoObject() {
-    return geoObject;
-  }
-
-  /**
-   * Returns the bounds of the geo object.
-   */
-  public Envelope getEnvelope() {
-    return envelope;
-  }
-
-  /**
-   * Returns the {@link CoordinateReferenceSystem} of the geo object.
-   */
-  public CoordinateReferenceSystem getCrs() {
-    return crs;
-  }
-
-  /**
-   * Returns {@link #crs CoordinateReferenceSystem.toString()}. This method
-   * can be overriden to create a "nicer" description.
-   */
-  public String getCRSString() {
-    return crs.toString();
-  }
-
-  /**
-   * Returns an icon, which represents the geo object.
-   */
-  public ImageIcon getImageIcon() {
-    return null;
-  }
-
-  /**
-   * Sets an icon, which represents the geo object.
-   * @param icon an icon
-   */
-  public void setImageIcon(ImageIcon icon) {
-    this.icon = icon;
-  }
-
-  /**
-   * Returns the display style for the geo object.
-   */
-  public Style getStyle() {
-    return style;
-  }
-
-  /**
-   * Sets the display style for the geo object.
-   * If {@code style} is {@code null} an default style is set, so
-   * {@link #getStyle()} never returns {@code null}.
-   * @see #createDefaultStyle()
-   */
-  public void setStyle(Style style) {
-    this.style = (style != null) ? style : createDefaultStyle();
-  }
-
-  /**
-   * Creates a default style for the geo object. This style is used whenever
-   * the style is set to {@code null}.
-   * @see #setStyle(Style)
-   */
-  protected abstract Style createDefaultStyle();
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package skrueger.geotools;
+
+import javax.swing.ImageIcon;
+
+import org.apache.log4j.Logger;
+import org.geotools.styling.Style;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+
+import schmitzm.lang.LangUtil;
+import skrueger.i8n.Translation;
+
+import com.vividsolutions.jts.geom.Envelope;
+
+/**
+ * This class is a default implementation of {@link StyledLayerInterface}.
+ * {@link StyledLayerInterface#dispose()} and {@link StyledLayerInterface#uncache()}
+ * must be implemented by the sub class. This class only implements the "hold"
+ * of an geo object of type {@code <E>}.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public abstract class AbstractStyledLayer<E> implements StyledLayerInterface<E> {
+  /** Logger for warning- and error messages. */
+  protected Logger LOGGER = LangUtil.createLogger(this);
+
+  /** Holds the unique ID of the geo object. */
+  protected String id = null;
+  /** Holds a short (language-specific) description of the geo object. */
+  protected Translation title = null;
+  /** Holds a long (language-specific) description of the geo object. */
+  protected Translation desc = null;
+  /** Holds the (language-specific) keywords to describe the geo object. */
+  protected Translation keywords = null;
+  /** Holds an icon to represent the geo object */
+  protected ImageIcon icon = null;
+  /** Holds the geo object represeneted by the map */
+  protected E geoObject = null;
+  /** Holds the CRS of the geo object */
+  protected CoordinateReferenceSystem crs = null;
+  /** Holds the bounds of the geo object */
+  protected Envelope envelope = null;
+  /** Holds the display style for the geo object */
+  protected Style style = null;
+
+  /**
+   * Creates a language specific styled layer.
+   * @param geoObject the geo object
+   * @param envelope the bounds of the geo object
+   * @param crs the CRS of the geo object
+   * @param id a unique ID for the geo object
+   * @param title a (language-specific) short description
+   * @param desc a (language-specific) long description
+   * @param keywords (language-specific) keywords for the geo objects
+   * @param style a display style
+   * @param icon an icon for the object
+   * @exception IllegalArgumentException if {@code null} is given as ID or
+   *            geo object
+   */
+  public AbstractStyledLayer(E geoObject, Envelope envelope, CoordinateReferenceSystem crs, String id, Translation title, Translation desc, Translation keywords, Style style, ImageIcon icon) {
+    if ( id == null )
+      throw new IllegalArgumentException("ID is not allowed to be null!");
+    if ( geoObject == null )
+      throw new IllegalArgumentException("The GeoObject is not allowed to be null!");
+    this.id        = id;
+    this.geoObject = geoObject;
+    this.crs       = crs;
+    this.envelope  = envelope;
+    setTitle( title );
+    setDesc( desc );
+    setKeywords( keywords );
+    setStyle( style );
+    setImageIcon( icon );
+  }
+
+  /**
+   * Creates a non-translated styled layer.
+   * @param geoObject the geo object
+   * @param envelope the bounds of the geo object
+   * @param crs the CRS of the geo object
+   * @param id a unique ID for the geo object
+   * @param title a short description
+   * @param desc a long description
+   * @param keywords keywords for the geo objects
+   * @param style a display style
+   * @param icon an icon for the object
+   * @exception IllegalArgumentException if {@code null} is given as ID
+   */
+  public AbstractStyledLayer(E geoObject, Envelope envelope, CoordinateReferenceSystem crs, String id, String title, String desc, String keywords, Style style, ImageIcon icon ) {
+    this(geoObject, envelope, crs, id, (Translation)null, null, null, style, icon);
+    setTitle( title );
+    setDesc( desc );
+    setKeywords( keywords );
+  }
+
+  /**
+   * Returns a ID for the geo object. The ID should be unique in a map ob
+   * {@linkplain StyledLayerInterface styled layer objects}
+   */
+  public String getId() {
+    return id;
+  }
+
+  /**
+   * Returns a short (language-specific) description of the geo object.
+   */
+  public Translation getTitle() {
+    return title;
+  }
+
+  /**
+   * Sets a short (language-specific) description of the geo object.
+   * If {@code title} is {@code null} an untranslated default title is set, so
+   * {@link #getTitle()} never returns {@code null}.
+   * @param title new description for the geo object
+   */
+  public void setTitle(Translation title) {
+    this.title = (title != null) ? title : new Translation("untitled");
+  }
+
+  /**
+   * Sets a short (non-translated) description of the geo object.
+   * If {@code title} is {@code null} an untranslated default title is set, so
+   * {@link #getTitle()} never returns {@code null}.
+   * @param title new description for the geo object
+   */
+  public void setTitle(String title) {
+    setTitle( title != null ? new Translation(title): (Translation)null );
+  }
+
+  /**
+   * Returns a long (language-specific) description of the object.
+   */
+  public Translation getDesc() {
+    return desc;
+  }
+
+  /**
+   * Sets a long (language-specific) description of the object.
+   * If {@code desc} is {@code null} an (untranslated) empty description is set, so
+   * {@link #getDesc()} never returns {@code null}.
+   * @param desc new description for the geo object
+  */
+  public void setDesc(Translation desc) {
+    this.desc = (desc != null) ? desc : new Translation("");
+  }
+
+  /**
+   * Sets a long (non-translated) description of the object.
+   * If {@code desc} is {@code null} an (untranslated) empty description is set, so
+   * {@link #getDesc()} never returns {@code null}.
+   * @param desc new description for the geo object
+  */
+  public void setDesc(String desc) {
+    setDesc( desc != null ? new Translation(desc) : (Translation)null);
+  }
+
+  /**
+   * Returns a (language-specific) key word sequence for the geo object.
+   */
+  public Translation getKeywords() {
+    return keywords;
+  }
+
+  /**
+   * Sets a (language-specific) key word sequence for the geo object.
+   * If {@code keywords} is {@code null} an (untranslated) empty string is set, so
+   * {@link #getKeywords()} never returns {@code null}.
+   * @param keywords Keywords
+   */
+  public void setKeywords(Translation keywords) {
+    this.keywords = (keywords != null) ? keywords : new Translation("");
+  }
+
+  /**
+   * Sets a (non-translated) key word sequence for the geo object.
+   * If {@code keywords} is {@code null} an (untranslated) empty string is set, so
+   * {@link #getKeywords()} never returns {@code null}.
+   * @param keywords Keywords
+   */
+  public void setKeywords(String keywords) {
+    setKeywords( keywords != null ? new Translation(keywords) : (Translation)null);
+  }
+
+  /**
+   * Returns the geo object representet in the map. Sub classes must override
+   * this method to implement "late loading" on first call.
+   * @return {@link #geoObject}
+   */
+  public E getGeoObject() {
+    return geoObject;
+  }
+
+  /**
+   * Returns the bounds of the geo object.
+   */
+  public Envelope getEnvelope() {
+    return envelope;
+  }
+
+  /**
+   * Returns the {@link CoordinateReferenceSystem} of the geo object.
+   */
+  public CoordinateReferenceSystem getCrs() {
+    return crs;
+  }
+
+  /**
+   * Returns {@link #crs CoordinateReferenceSystem.toString()}. This method
+   * can be overriden to create a "nicer" description.
+   */
+  public String getCRSString() {
+    return crs.toString();
+  }
+
+  /**
+   * Returns an icon, which represents the geo object.
+   */
+  public ImageIcon getImageIcon() {
+    return null;
+  }
+
+  /**
+   * Sets an icon, which represents the geo object.
+   * @param icon an icon
+   */
+  public void setImageIcon(ImageIcon icon) {
+    this.icon = icon;
+  }
+
+  /**
+   * Returns the display style for the geo object.
+   */
+  public Style getStyle() {
+    return style;
+  }
+
+  /**
+   * Sets the display style for the geo object.
+   * If {@code style} is {@code null} an default style is set, so
+   * {@link #getStyle()} never returns {@code null}.
+   * @see #createDefaultStyle()
+   */
+  public void setStyle(Style style) {
+    this.style = (style != null) ? style : createDefaultStyle();
+  }
+
+  /**
+   * Creates a default style for the geo object. This style is used whenever
+   * the style is set to {@code null}.
+   * @see #setStyle(Style)
+   */
+  protected abstract Style createDefaultStyle();
+}

Modified: trunk/src/skrueger/geotools/AttributeTableJDialog.java
===================================================================
--- trunk/src/skrueger/geotools/AttributeTableJDialog.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/AttributeTableJDialog.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,3 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 //package skrueger.geotools;
 //
 //import java.awt.Component;

Modified: trunk/src/skrueger/geotools/LegendIconFeatureRenderer.java
===================================================================
--- trunk/src/skrueger/geotools/LegendIconFeatureRenderer.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/LegendIconFeatureRenderer.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,3 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 /** 
  Copyright 2008 Stefan Alfons Krüger and parts from some Geotools code  
  

Modified: trunk/src/skrueger/geotools/MapContextManagerInterface.java
===================================================================
--- trunk/src/skrueger/geotools/MapContextManagerInterface.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/MapContextManagerInterface.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,87 +1,116 @@
-package skrueger.geotools;
-import java.util.List;
-
-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;
-
-/**
- * Implementations of this class can can be used to fill/insert/remove a mapContext
- * with {@link StyledLayerInterface} objects.
- *
- * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
- *
- */
-public interface MapContextManagerInterface {
-
-	/**
-	 * Add a {@link StyledLayerInterface} object into the underlying {@link MapContext}
-	 * as the topmost layer
-	 *
-	 * @param styledLayer Layer to add to the map
-	 */
-	boolean addStyledLayer (StyledLayerInterface<?> styledLayer);
-
-	/**
-	 * @param mapContextIdx Index in the {@link MapContext}, bottom first
-	 * @return successful?
-	 */
-	boolean removeStyledLayer (int mapContextIdx);
-
-	/**
-	 * Inserts a {@link StyledLayerInterface} object into the underlying {@link MapContext}
-	 * at the given position
-	 */
-	boolean insertStyledLayer (StyledLayerInterface<?> styledLayer, int mapContextIdx);
-
-	/** Add {@link MapLayerListener} */
-	void addMapLayerListListener( MapLayerListListener listener);
-
-	/** Remove {@link MapLayerListener} */
-	void removeMapLayerListListener( MapLayerListListener listener);
-
-	/**
-	 * Help the GC by disposing this Component
-	 */
-	void dispose();
-
-	/**
-	 * Returns a ordered list of the layers that are contained in the underlying {@link MapContext}
-	 */
-	List<StyledLayerInterface<?>> getStyledObjects();
-
-	/**
-	 * Returns a list of {@link AttributeMetaData} that shall be shown (e.g. when the Mouse clicked into the map)
-	 * Returns an empty list if the layer doesn't exist or is not backed by a {@link StyledFeatureCollectionInterface}
-	 */
-	List<AttributeMetaData> getVisibleAttribsFor(MapLayer mapLayer);
-
-	/**
-	 * Returns the title of the layer
-	 * @param mapLayer {@link MapLayer}
-	 * @return <code>null</code>, if the layer is unknown
-	 */
-	String getTitleFor(MapLayer mapLayer);
-
-	/**
-	 * Returns the description of the layer
-	 * @param mapLayer {@link MapLayer}
-	 * @return <code>null</code>, if the layer is unknown. Empty String if the description is empty
-	 */
-	String getDescFor(MapLayer mapLayer);
-
-	/**
-	 * Returns the {@link RasterLegendData} object for the layer.
-	 * @return null, if the layer is not found or of type raster
-	 */
-	RasterLegendData getLegendMetaData(MapLayer mapLayer);
-
-	/**
-	 * Returns the {@link StyledLayerInterface} object that is associated with the layer or NULL if the layer can't be found.
-	 */
-	StyledLayerInterface<?> getStyledObjectFor(MapLayer layer);
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package skrueger.geotools;
+import java.util.List;
+
+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;
+
+/**
+ * Implementations of this class can can be used to fill/insert/remove a mapContext
+ * with {@link StyledLayerInterface} objects.
+ *
+ * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
+ *
+ */
+public interface MapContextManagerInterface {
+
+	/**
+	 * Add a {@link StyledLayerInterface} object into the underlying {@link MapContext}
+	 * as the topmost layer
+	 *
+	 * @param styledLayer Layer to add to the map
+	 */
+	boolean addStyledLayer (StyledLayerInterface<?> styledLayer);
+
+	/**
+	 * @param mapContextIdx Index in the {@link MapContext}, bottom first
+	 * @return successful?
+	 */
+	boolean removeStyledLayer (int mapContextIdx);
+
+	/**
+	 * Inserts a {@link StyledLayerInterface} object into the underlying {@link MapContext}
+	 * at the given position
+	 */
+	boolean insertStyledLayer (StyledLayerInterface<?> styledLayer, int mapContextIdx);
+
+	/** Add {@link MapLayerListener} */
+	void addMapLayerListListener( MapLayerListListener listener);
+
+	/** Remove {@link MapLayerListener} */
+	void removeMapLayerListListener( MapLayerListListener listener);
+
+	/**
+	 * Help the GC by disposing this Component
+	 */
+	void dispose();
+
+	/**
+	 * Returns a ordered list of the layers that are contained in the underlying {@link MapContext}
+	 */
+	List<StyledLayerInterface<?>> getStyledObjects();
+
+	/**
+	 * Returns a list of {@link AttributeMetaData} that shall be shown (e.g. when the Mouse clicked into the map)
+	 * Returns an empty list if the layer doesn't exist or is not backed by a {@link StyledFeatureCollectionInterface}
+	 */
+	List<AttributeMetaData> getVisibleAttribsFor(MapLayer mapLayer);
+
+	/**
+	 * Returns the title of the layer
+	 * @param mapLayer {@link MapLayer}
+	 * @return <code>null</code>, if the layer is unknown
+	 */
+	String getTitleFor(MapLayer mapLayer);
+
+	/**
+	 * Returns the description of the layer
+	 * @param mapLayer {@link MapLayer}
+	 * @return <code>null</code>, if the layer is unknown. Empty String if the description is empty
+	 */
+	String getDescFor(MapLayer mapLayer);
+
+	/**
+	 * Returns the {@link RasterLegendData} object for the layer.
+	 * @return null, if the layer is not found or of type raster
+	 */
+	RasterLegendData getLegendMetaData(MapLayer mapLayer);
+
+	/**
+	 * Returns the {@link StyledLayerInterface} object that is associated with the layer or NULL if the layer can't be found.
+	 */
+	StyledLayerInterface<?> getStyledObjectFor(MapLayer layer);
+}

Modified: trunk/src/skrueger/geotools/MapPaneToolBar.java
===================================================================
--- trunk/src/skrueger/geotools/MapPaneToolBar.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/MapPaneToolBar.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,819 +1,848 @@
-package skrueger.geotools;
-
-import java.awt.Color;
-import java.awt.Dimension;
-import java.awt.Graphics;
-import java.awt.event.ActionEvent;
-import java.util.ArrayList;
-import java.util.Locale;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-import javax.swing.AbstractAction;
-import javax.swing.AbstractButton;
-import javax.swing.Action;
-import javax.swing.BorderFactory;
-import javax.swing.Icon;
-import javax.swing.ImageIcon;
-import javax.swing.JButton;
-import javax.swing.JComponent;
-import javax.swing.JToggleButton;
-import javax.swing.JToolBar;
-
-import org.apache.log4j.Logger;
-
-import schmitzm.geotools.gui.JMapPane;
-import schmitzm.geotools.map.event.JMapPaneEvent;
-import schmitzm.geotools.map.event.JMapPaneListener;
-import schmitzm.geotools.map.event.MapAreaChangedEvent;
-import schmitzm.lang.LangUtil;
-import schmitzm.lang.ResourceProvider;
-import schmitzm.swing.ButtonGroup;
-import schmitzm.swing.SwingUtil;
-
-import com.vividsolutions.jts.geom.Envelope;
-
-/**
- * A toolbar to control an {@link JMapPane} (Atlas visualization). This contains
- * two types of buttons. A group of <i>tools</i> for the mouse actions on the
- * map represented by {@link JToggleButton JToggleButtons}, where only one tool
- * can be activated every time. And some (general) <i>actions</i>, represented
- * by normal {@link JButton JButtons}.
- * 
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- *         (University of Bonn/Germany)
- * @version 1.2 Stefan Krüger
- */
-public class MapPaneToolBar extends JToolBar {
-	private static final Logger LOGGER = Logger.getLogger(MapPaneToolBar.class
-			.getName());
-	
-	public static ResourceProvider RESOURCE = new ResourceProvider(LangUtil
-			.extendPackagePath(MapPaneToolBar.class,
-					"resource.locales.mapPaneToolbar"), Locale.ENGLISH);
-	
-	public static String R(String key, Object... values) {
-		return RESOURCE.getString(key, values);
-	}
-
-	/** Constant for the tool "Panning" (10). */
-	public static final int TOOL_PAN = 10;
-	/** Constant for the tool "Info" (20). */
-	public static final int TOOL_INFO = 20;
-	public static final int SEPERATOR0 = 99;
-
-	/** Constant for the tool "Zoom In" (110). */
-	public static final int TOOL_ZOOMIN = 110;
-	/** Constant for the tool "Zoom Out" (120). */
-	public static final int TOOL_ZOOMOUT = 120;
-	/** Constant for the action "Zoom back" (130). */
-	public static final int ACTION_ZOOM_BACK = 130;
-	/** Constant for the action "Zoom forward" (140). */
-	public static final int ACTION_ZOOM_FORWARD = 140;
-	public static final int SEPERATOR1 = 199;
-
-	/**
-	 * Constant for the tool "Selection Reset" which clears the selection (240).
-	 */
-	public static final int TOOL_SELECTION_CLEAR = 240;
-
-	/**
-	 * Constant for the tool "Select" which sets the Selection to the selected
-	 * features (210).
-	 */
-	public static final int TOOL_SELECTION_SET = 210;
-	/**
-	 * Constant for the tool "Selection add" which adds the features to the
-	 * Selection (220).
-	 */
-	public static final int TOOL_SELECTION_ADD = 220;
-	/**
-	 * Constant for the tool "Selection subtract" which removes the selected
-	 * features from the selection (230).
-	 */
-	public static final int TOOL_SELECTION_REMOVE = 230;
-
-	/** Tool currently selected */
-	protected int selectedTool = TOOL_ZOOMIN;
-
-	/** Holds the tool buttons of the tool bar. */
-	protected SortedMap<Integer, JComponent> toolAndActionButtons = null;
-	/** Controls that only one tool button is activated. */
-	protected ButtonGroup toolButtonGroup = null;
-
-	// SK: Musste ich ändern damit man Tools und Actions in der Reihenfolge
-	// mischen kann.
-	// /** Holds the action buttons of the bar. */
-	// protected SortedMap<Integer, JButton> actionButtons = null;
-
-	/** Holds the {@link JMapPane} this tool bar controls. */
-	protected JMapPane mapPane = null;
-
-	/**
-	 * A List to remember the last Envelopes that have been watched. Used for
-	 * the zoomBack- and zoomForwardButtons *
-	 */
-	protected ArrayList<Envelope> lastZooms = new ArrayList<Envelope>();
-	/** Holds the index to the current element in {@link #lastZooms}. */
-	protected int zoomBackIndex = 0;
-
-	/** Listener to sniff the zoom actions on the map. */
-	protected JMapPaneListener mapPaneListener = null;
-
-	protected boolean zoomBackForwardButtonInAction;
-
-	/**
-	 * Creates a new toolbar. Notice: This toolbar does nothing until
-	 * {@link #setMapPane(JMapPane)} is called!
-	 */
-	public MapPaneToolBar() {
-		this(null);
-	}
-
-	/**
-	 * Creates a new tool bar.
-	 * 
-	 * @param mapPane
-	 *            {@link JMapPane} the tool bar controls
-	 */
-	public MapPaneToolBar(JMapPane mapPane) {
-		super("Control the map", JToolBar.HORIZONTAL);
-		this.toolAndActionButtons = new TreeMap<Integer, JComponent>();
-		this.toolButtonGroup = new ButtonGroup();
-		
-		// Create a Listener to listen to the zooms on the JMapPane
-		this.mapPaneListener = new JMapPaneListener() {
-			public void performMapPaneEvent(JMapPaneEvent e) {
-				if (!(e instanceof MapAreaChangedEvent))
-					return;
-
-				if (zoomBackForwardButtonInAction) {
-					zoomBackForwardButtonInAction = false;
-					return;
-				}
-
-				final MapAreaChangedEvent mapAreaChangedEvent = (MapAreaChangedEvent) e;
-				Envelope oldMapArea = mapAreaChangedEvent.getOldMapArea();
-				
-				final Envelope mapArea = mapAreaChangedEvent.getNewMapArea();
-				if (mapArea == null || mapArea.equals(oldMapArea) ) {
-					// If the MapArea didn't change... we don't want to register it as a zoom action.
-					return;
-				}
-				
-				if (lastZooms.size() == 0 && oldMapArea != null) {
-					lastZooms.add(oldMapArea);
-					zoomBackIndex = 1;
-				}
-				if (mapArea == null)
-					return;
-
-				if (lastZooms.size() > 0
-						&& mapArea.equals(lastZooms.get(lastZooms.size() - 1))) {
-					// LOGGER.debug("MapAreaChangedEvent ausgelassen bei der Zaehlung der Zoomschritt weil identisch");
-					return;
-				}
-
-				if (lastZooms.size() > 0)
-					while (zoomBackIndex < lastZooms.size())
-						lastZooms.remove(lastZooms.size() - 1);
-
-				lastZooms.add(mapArea);
-				zoomBackIndex = lastZooms.size();
-				setButtonEnabled(ACTION_ZOOM_BACK, lastZooms.size() > 1);
-				setButtonEnabled(ACTION_ZOOM_FORWARD, false);
-			}
-		};
-
-		setMapPane(mapPane);
-		setFloatable(false);
-		setRollover(true);
-
-		init();
-	}
-
-	/**
-	 * Sets the {@link JMapPane} controlled by this tool bar.
-	 * 
-	 * @param mapPane
-	 *            {@link JMapPane} to control (if {@code null} this tool bar
-	 *            controls NOTHING!)
-	 */
-	public void setMapPane(JMapPane mapPane) {
-		// Remove listener from old MapPane
-		if (this.mapPane != null)
-			this.mapPane.removeMapPaneListener(mapPaneListener);
-		this.mapPane = mapPane;
-		if (this.mapPane != null && mapPaneListener != null)
-			this.mapPane.addMapPaneListener(mapPaneListener);
-	}
-
-	/**
-	 * Calls {@link #initToolsAndActions()} and {@link #initActions()} and then
-	 * puts all tool buttons and all actions buttons to the tool bar.
-	 */
-	protected void init() {
-		initToolsAndActions();
-
-		addSeparator(SEPERATOR0, new JToolBar.Separator());
-		addSeparator(SEPERATOR1, new JToolBar.Separator());
-
-		initToolBar();
-	}
-
-	/**
-	 * Creates the tool buttons and action buttons and seperators, adds them to
-	 * {@link #toolAndActionButtons} and finally creates a button group for all
-	 * tools. So sub-classes which override this method should FIRST add their
-	 * new tool buttons to {@link #toolAndActionButtons} before calling {@code
-	 * super.initTools()}.
-	 */
-	protected void initToolsAndActions() {
-		// Panning
-		addTool(new MapPaneToolBarAction(TOOL_PAN, this, "", new ImageIcon(
-				MapView.class.getResource("resource/icons/pan.png")), R("MapPaneButtons.Pan.TT")), false);
-		// Info
-		addTool(new MapPaneToolBarAction(TOOL_INFO, this, "", new ImageIcon(
-				MapView.class.getResource("resource/icons/info.png")),R("MapPaneButtons.Info.TT")), false);
-
-		// Zoom in
-		addTool(new MapPaneToolBarAction(TOOL_ZOOMIN, this, "", new ImageIcon(
-				MapView.class.getResource("resource/icons/zoom_in.png")), R("MapPaneButtons.ZoomIn.TT")),
-				false);
-		// Zoom out
-		addTool(new MapPaneToolBarAction(TOOL_ZOOMOUT, this, "", new ImageIcon(
-				MapView.class.getResource("resource/icons/zoom_out.png")), R("MapPaneButtons.ZoomOut.TT")),
-				false);
-
-		// Action button to revert the last zoom
-		addAction(new MapPaneToolBarAction(ACTION_ZOOM_BACK, this, "",
-				new ImageIcon(MapView.class
-						.getResource("resource/icons/zoom_back.png")), R("MapPaneButtons.LastZoom.TT")), false);
-		setButtonEnabled(ACTION_ZOOM_BACK, false);
-
-		// Action button to redo the last zoom
-		addAction(new MapPaneToolBarAction(ACTION_ZOOM_FORWARD, this, "",
-				new ImageIcon(MapView.class
-						.getResource("resource/icons/zoom_forward.png")), R("MapPaneButtons.NextZoom.TT")),
-				false);
-		setButtonEnabled(ACTION_ZOOM_FORWARD, false);
-
-		// set the selected tool enabled
-		setSelectedTool(selectedTool);
-
-	}
-
-	/**
-	 * Clears the GUI of all components and adds all tool and action buttons to
-	 * the tool bar.
-	 */
-	public void initToolBar() {
-		setAlignmentY(1f);
-		removeAll();
-		// Separator to the left of the tool actions to start
-		// the tool buttons with the map (not with the coordinate grid)
-		Dimension dimension = new Dimension(49, 10);
-		addSeparator(dimension);
-		// Tool buttons
-		for (JComponent b : toolAndActionButtons.values())
-			add(b);
-
-		if (!toolAndActionButtons.containsKey(selectedTool)) {
-			/**
-			 * This might be a bit specific, but IF selection buttons are
-			 * available, select one of them.. if not, select the INFO tool.
-			 */
-
-			if (toolAndActionButtons.containsKey(TOOL_SELECTION_SET)) {
-				setSelectedTool(TOOL_SELECTION_SET);
-			} else if (toolAndActionButtons.containsKey(TOOL_INFO)) {
-				setSelectedTool(TOOL_INFO);
-			} else {
-				// TODO What to do now?!
-				setSelectedTool(null);
-			}
-
-		}
-		
-		revalidate();
-		repaint();
-	}
-
-	// Space between tool buttons and action buttons
-	// SK: Seperators are now als manages like actions and tools
-	// Dimension dimension2 = new Dimension( 10,10);
-	// this.addSeparator(dimension2);
-
-	// // Action buttons
-	// for (JButton b : actionButtons.values())
-	// add(b);
-	// }
-
-	/**
-	 * Performs the activation of a tool.
-	 * 
-	 * @param tool
-	 *            the tool to activate
-	 * @param e
-	 *            the event of the button
-	 */
-	public void performToolButton(int tool, ActionEvent e) {
-		if (mapPane == null)
-			return;
-
-		selectedTool = tool;
-
-		switch (tool) {
-		case TOOL_PAN:
-			// Set the mouse tool to "Panning"
-			mapPane.setWindowSelectionState(JMapPane.NONE);
-			mapPane.setState(JMapPane.PAN);
-			mapPane.setHighlight(false);
-			mapPane.setNormalCursor(SwingUtil.PAN_CURSOR);
-			break;
-		case TOOL_INFO:
-			// Set the mouse tool to "Info"
-			mapPane.setWindowSelectionState(JMapPane.NONE);
-			mapPane.setState(JMapPane.SELECT_TOP); // Why not:
-			// JMapPane.SELECT_TOP_ONEONLY
-			mapPane.setHighlight(false);// SK: Was true, but since it not works
-			// properly removed it to save
-			// performance
-			mapPane.setNormalCursor(SwingUtil.CROSSHAIR_CURSOR);
-			break;
-		case TOOL_ZOOMIN:
-			// Set the mouse tool to "Zoom in"
-			mapPane.setWindowSelectionState(JMapPane.ZOOM_IN);
-			mapPane.setState(JMapPane.ZOOM_IN);
-			mapPane.setHighlight(false);
-			mapPane.setNormalCursor(SwingUtil.ZOOMIN_CURSOR);
-			break;
-		case TOOL_ZOOMOUT:
-			// Set the mouse tool to "Zoom out"
-			mapPane.setWindowSelectionState(JMapPane.NONE);
-			mapPane.setState(JMapPane.ZOOM_OUT);
-			mapPane.setHighlight(false);
-			mapPane.setNormalCursor(SwingUtil.ZOOMOUT_CURSOR);
-			break;
-		default:
-			// Set map actions to default
-			mapPane.setWindowSelectionState(JMapPane.NONE);
-			mapPane.setState(JMapPane.NONE);
-			mapPane.setHighlight(false);
-			mapPane.setNormalCursor(null);
-			break;
-		}
-		mapPane.updateCursor();
-	}
-
-	/**
-	 * @param id
-	 *            The ID of the Component to remove. The change will not be
-	 *            visible until {@link #initToolBar()} is called.
-	 * @return <code>null</code> or the component that has been removed.
-	 */
-	public JComponent removeId(int id) {
-		return toolAndActionButtons.remove(id);
-	}
-
-	/**
-	 * Performs the action of an action button.
-	 * 
-	 * @param tool
-	 *            the action
-	 * @param e
-	 *            the event of the button
-	 */
-	protected void performActionButton(int action, ActionEvent e) {
-		if (mapPane == null)
-			return;
-
-		// Perform the action "Zoom back": Revert the last zoom
-		if (action == ACTION_ZOOM_BACK) {
-			if (zoomBackIndex <= 1)
-				return;
-
-			zoomBackForwardButtonInAction = true;
-			zoomBackIndex--;
-			getButton(ACTION_ZOOM_FORWARD).setEnabled(true);
-			getButton(ACTION_ZOOM_BACK).setEnabled(zoomBackIndex > 1);
-
-			mapPane.setMapArea(lastZooms.get(zoomBackIndex - 1));
-			mapPane.refresh();
-		}
-
-		// Perform the action "Zoom forward": Re-do the last zoom
-		if (action == ACTION_ZOOM_FORWARD) {
-			if (zoomBackIndex < lastZooms.size()) {
-				zoomBackForwardButtonInAction = true;
-				zoomBackIndex++;
-				getButton(ACTION_ZOOM_BACK).setEnabled(true);
-				getButton(ACTION_ZOOM_FORWARD).setEnabled(
-						zoomBackIndex < lastZooms.size());
-
-				mapPane.setMapArea(lastZooms.get(zoomBackIndex - 1));
-				mapPane.refresh();
-			}
-		}
-	}
-
-	/**
-	 * Adds a tool to the tool bar. Does nothing if a tool or action with the
-	 * specified ID already exists!
-	 * 
-	 * @param buttonAction
-	 *            action for the toggle button
-	 * @param resetToolBar
-	 *            indicates whether the toolbar GUI is reset after adding the
-	 *            button (if adding several actions it useful only to reset the
-	 *            GUI for the last added tool)
-	 */
-	public void addTool(MapPaneToolBarAction buttonAction, boolean resetToolBar) {
-		if (isButtonIDUsed(buttonAction.getID())) {
-			LOGGER
-					.warn("addTool(.) ignored because ID already used for tool or action: "
-							+ buttonAction.getID());
-			return;
-		}
-		JToggleButton button = new JToggleButton(buttonAction);
-		button.setBorder(BorderFactory.createRaisedBevelBorder());
-		toolButtonGroup.add(button);
-		toolAndActionButtons.put(buttonAction.getID(), button);
-		if (resetToolBar)
-			initToolBar();
-	}
-
-	/**
-	 * Adds a tool to the tool bar and resets the toolbar GUI.
-	 * 
-	 * @param buttonAction
-	 *            action for the toggle button
-	 */
-	public void addTool(MapPaneToolBarAction buttonAction) {
-		addTool(buttonAction, true);
-	}
-
-	/**
-	 * Adds an action to the tool bar. Does nothing if a tool or action with the
-	 * specified ID already exists!
-	 * 
-	 * @param buttonAction
-	 *            action for the button
-	 * @param resetToolBar
-	 *            indicates whether the toolbar GUI is reset after adding the
-	 *            button (if adding several actions it useful only to reset the
-	 *            GUI for the last added tool)
-	 */
-	public void addAction(MapPaneToolBarAction buttonAction,
-			boolean resetToolBar) {
-		if (isButtonIDUsed(buttonAction.getID())) {
-			LOGGER
-					.warn("addAction(.) ignored because ID already used for tool or action: "
-							+ buttonAction.getID());
-			return;
-		}
-		JButton button = new JButton(buttonAction);
-		button.setBorder(BorderFactory.createRaisedBevelBorder());
-		toolAndActionButtons.put(buttonAction.getID(), button);
-		if (resetToolBar)
-			initToolBar();
-	}
-
-	public void addSeparator(int id, Separator separator) {
-		if (isButtonIDUsed(id)) {
-			LOGGER
-					.warn("addSeparator(.) ignored because ID already used for tool or action. ");
-			return;
-		}
-		toolAndActionButtons.put(id, separator);
-	}
-
-	/**
-	 * Adds an action to the tool bar and resets the toolbar GUI.
-	 * 
-	 * @param buttonAction
-	 *            action for the toggle button
-	 */
-	public void addAction(MapPaneToolBarAction buttonAction) {
-		addAction(buttonAction, true);
-	}
-
-	/**
-	 * Returns the button for a specific tool or action.
-	 * 
-	 * @param id
-	 *            the constant for any button in the {@link MapPaneToolBar}
-	 * @return a {@link JButton} if {@code id} specifies an
-	 *         {@linkplain #getActionButton(int) action button} or
-	 *         {@link JToogleButton} if {@code id} specifies a
-	 *         {@linkplain #getToolButton(int) tool button}
-	 */
-	public AbstractButton getButton(int id) {
-		AbstractButton button = (AbstractButton) toolAndActionButtons.get(id);
-		if (button == null)
-			LOGGER.warn("Unknown tool or action ID: " + id);
-		return button;
-	}
-
-	/**
-	 * Returns the button for a specific tool.
-	 * 
-	 * @param tool
-	 *            the constant for a tool
-	 */
-	public JToggleButton getToolButton(int tool) {
-		AbstractButton button = getButton(tool);
-		if (button != null && !(button instanceof JToggleButton)) {
-			LOGGER.warn("ID specifies no tool: " + tool);
-			button = null;
-		}
-		return (JToggleButton) button;
-	}
-
-	/**
-	 * Returns the button for a specific action.
-	 * 
-	 * @param action
-	 *            the constant an action
-	 */
-	public JButton getActionButton(int action) {
-		AbstractButton button = getButton(action);
-		if (button != null && !(button instanceof JButton)) {
-			LOGGER.warn("ID specifies no action: " + action);
-			button = null;
-		}
-		return (JButton) button;
-
-	}
-
-	/**
-	 * Sets the selected tool.
-	 * 
-	 * @param tool
-	 *            ID of the tool
-	 */
-	public void setSelectedTool(Integer tool) {
-		if (tool == null)
-			toolButtonGroup.setUnselected();
-
-		JToggleButton button = getToolButton(tool);
-		if (button == null)
-			return;
-		button.setSelected(true);
-		button.getAction().actionPerformed(null);
-
-		selectedTool = tool;
-	}
-
-	/**
-	 * Returns the selected tool.
-	 * 
-	 * @return -1 if no tool is active
-	 */
-	public int getSelectedTool() {
-		if (toolButtonGroup.getSelectedButton() == null)
-			return -1;
-		return selectedTool;
-	}
-
-	/**
-	 * Sets whether a tool or action is activated or not. The visible property
-	 * of the button is not affected.
-	 * 
-	 * @param id
-	 *            tool or actionID
-	 * @param enabled
-	 *            if {@code true} the tool becomes available
-	 */
-	public void setButtonEnabled(int id, boolean enabled) {
-		AbstractButton button = getButton(id);
-		if (button == null)
-			return;
-		button.setEnabled(enabled);
-	}
-
-	/**
-	 * Sets whether a tool or action is activated or not.
-	 * 
-	 * @param id
-	 *            tool or actionID
-	 * @param enabled
-	 *            if {@code true} the tool becomes available
-	 * @param hideOnDisable
-	 *            if {@code true} the button is also hidden if {@code enabled}
-	 *            is {@code false}
-	 */
-	public void setButtonEnabled(int id, boolean enabled, boolean hideOnDisable) {
-		AbstractButton button = getButton(id);
-		if (button == null)
-			return;
-		button.setEnabled(enabled);
-		// if button is enabled, it becomes visible anyway
-		// if button is disabled and the "hide" option is set, it is also hidden
-		if (enabled)
-			button.setVisible(true);
-		else
-			button.setVisible(!hideOnDisable);
-	}
-
-	/**
-	 * Checks whether a ID is already used for a tool or action.
-	 * 
-	 * @param tool
-	 *            tool ID
-	 */
-	public boolean isButtonIDUsed(int id) {
-		return toolAndActionButtons.get(id) != null;
-	}
-
-	/**
-	 * Checks whether a tool is activated.
-	 * 
-	 * @param tool
-	 *            tool ID
-	 * @return {@code false} if an unknown ID is specified
-	 */
-	public boolean isButtonEnabled(int id) {
-		AbstractButton button = getButton(id);
-		if (button != null)
-			return button.isEnabled();
-		return false;
-	}
-
-	/**
-	 * Sets the activation for all tools.
-	 * 
-	 * @param enabled
-	 *            if {@code true} all tools becomes available
-	 * @param hideOnDisable
-	 *            if {@code true} the buttons are also hidden if {@code enabled}
-	 *            is {@code false}
-	 */
-	public void setAllToolsEnabled(boolean enabled, boolean hideOnDisable) {
-		for (int tool : toolAndActionButtons.keySet())
-			setButtonEnabled(tool, enabled, hideOnDisable);
-	}
-
-	/**
-	 * Sets the activation for all actions.
-	 * 
-	 * @param enabled
-	 *            if {@code true} all actions becomes available
-	 * @param hideOnDisable
-	 *            if {@code true} the buttons are also hidden if {@code enabled}
-	 *            is {@code false}
-	 */
-	public void setAllActionsEnabled(boolean enabled, boolean hideOnDisable) {
-		for (int id : toolAndActionButtons.keySet()) {
-			if (toolAndActionButtons.get(id) instanceof JButton) {
-				setButtonEnabled(id, enabled, hideOnDisable);
-			}
-		}
-
-	}
-
-	/**
-	 * Returns the maximum ID of tools.
-	 */
-	public int getMaxToolID() {
-		return toolAndActionButtons.lastKey();
-	}
-
-	/**
-	 * Returns the minimum ID of tools.
-	 */
-	public int getMinToolID() {
-		return toolAndActionButtons.firstKey();
-	}
-
-	/**
-	 * Extends the {@link AbstractAction} with maintaining an ID and the
-	 * {@link MapPaneToolBar} the actions controls. Additionally this class
-	 * automatically calls
-	 * {@link MapPaneToolBar#performToolButton(int, ActionEvent)} or
-	 * {@link MapPaneToolBar#performActionButton(int, ActionEvent)} depending on
-	 * whether the action is added via
-	 * {@link MapPaneToolBar#addTool(MapPaneToolBarAction)} or
-	 * {@link MapPaneToolBar#addAction(MapPaneToolBarAction)}.
-	 * 
-	 * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
-	 *         (University of Bonn/Germany)
-	 */
-	public static class MapPaneToolBarAction extends AbstractAction {
-		/** The ID of the action */
-		protected int id = -1;
-		/** The tool bar, this action is made for. */
-		protected MapPaneToolBar toolBar = null;
-
-		/**
-		 * Creates a new action with a dummy description and no icon.
-		 * 
-		 * @param id
-		 *            unique ID for the action
-		 * @param toolBar
-		 *            toolbar this action is made for
-		 */
-		public MapPaneToolBarAction(int id, MapPaneToolBar toolBar) {
-			this(id, toolBar, "" + id);
-		}
-
-		/**
-		 * Creates a new action without an icon.
-		 * 
-		 * @param id
-		 *            unique ID for the action
-		 * @param toolBar
-		 *            toolbar this action is made for
-		 * @param name
-		 *            description used for buttons or menus
-		 */
-		public MapPaneToolBarAction(int id, MapPaneToolBar toolBar, String name) {
-			this(id, toolBar, name, null);
-		}
-
-		/**
-		 * Creates a new action.
-		 * 
-		 * @param id
-		 *            unique ID for the action
-		 * @param toolBar
-		 *            toolbar this action is made for
-		 * @param name
-		 *            description used for buttons or menus
-		 * @param icon
-		 *            icon used for buttons or menus
-		 */
-		public MapPaneToolBarAction(int id, MapPaneToolBar toolBar,
-				String name, Icon icon) {
-			this (id, toolBar, name, icon, null);
-		}
-		
-		/**
-		 * Creates a new action.
-		 * 
-		 * @param id
-		 *            unique ID for the action
-		 * @param toolBar
-		 *            The {@link MapPaneToolBar} this action is made for
-		 * @param name
-		 *            description used for buttons or menus
-		 * @param icon
-		 *            icon used for buttons or menus
-		 * @param toolTip
-		 *            Tooltip to use for the button or menu
-		 */
-		public MapPaneToolBarAction(int id, MapPaneToolBar toolBar,
-				String name, Icon icon, String toolTip) {
-			super(name, icon);
-			
-			if (toolTip != null && !toolTip.trim().isEmpty()){
-				putValue(Action.SHORT_DESCRIPTION, toolTip);
-			}
-			
-			this.id = id;
-			this.toolBar = toolBar;
-		}
-
-		/**
-		 * Calls {@link MapPaneToolBar#performToolButton(int, ActionEvent)} or
-		 * {@link MapPaneToolBar#performActionButton(int, ActionEvent)}
-		 * depending on whether the action is added to the toolbar via
-		 * {@link MapPaneToolBar#addTool(MapPaneToolBarAction)} or
-		 * {@link MapPaneToolBar#addAction(MapPaneToolBarAction)}.
-		 */
-		public void actionPerformed(ActionEvent e) {
-			if (toolBar.toolAndActionButtons.get(id) instanceof JToggleButton)
-				toolBar.performToolButton(id, e);
-			else if (toolBar.toolAndActionButtons.get(id) instanceof JButton)
-				toolBar.performActionButton(id, e);
-		}
-
-		/**
-		 * Returns the (unique) id of this action.
-		 * 
-		 * @return
-		 */
-		public int getID() {
-			return id;
-		}
-	}
-	
-	  /**
-	   * Nuetzlich wenn die Componente gedruckt (z.B. wenn ein Screenshot gemacht wird) wird. Dann werden wird der
-	   * Hintergrund auf WEISS gesetzt.
-	   *
-	   * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	   *         Kr&uuml;ger</a>
-	   */
-	  @Override
-	  public void print(Graphics g) {
-	      Color orig = getBackground();
-	      setBackground(Color.WHITE);
-	      // wrap in try/finally so that we always restore the state
-	      try {
-	          super.print(g);
-	      } finally {
-	          setBackground(orig);
-	      }
-	  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package skrueger.geotools;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.Graphics;
+import java.awt.event.ActionEvent;
+import java.util.ArrayList;
+import java.util.Locale;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import javax.swing.AbstractAction;
+import javax.swing.AbstractButton;
+import javax.swing.Action;
+import javax.swing.BorderFactory;
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JToggleButton;
+import javax.swing.JToolBar;
+
+import org.apache.log4j.Logger;
+
+import schmitzm.geotools.gui.JMapPane;
+import schmitzm.geotools.map.event.JMapPaneEvent;
+import schmitzm.geotools.map.event.JMapPaneListener;
+import schmitzm.geotools.map.event.MapAreaChangedEvent;
+import schmitzm.lang.LangUtil;
+import schmitzm.lang.ResourceProvider;
+import schmitzm.swing.ButtonGroup;
+import schmitzm.swing.SwingUtil;
+
+import com.vividsolutions.jts.geom.Envelope;
+
+/**
+ * A toolbar to control an {@link JMapPane} (Atlas visualization). This contains
+ * two types of buttons. A group of <i>tools</i> for the mouse actions on the
+ * map represented by {@link JToggleButton JToggleButtons}, where only one tool
+ * can be activated every time. And some (general) <i>actions</i>, represented
+ * by normal {@link JButton JButtons}.
+ * 
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *         (University of Bonn/Germany)
+ * @version 1.2 Stefan Krüger
+ */
+public class MapPaneToolBar extends JToolBar {
+	private static final Logger LOGGER = Logger.getLogger(MapPaneToolBar.class
+			.getName());
+	
+	public static ResourceProvider RESOURCE = new ResourceProvider(LangUtil
+			.extendPackagePath(MapPaneToolBar.class,
+					"resource.locales.mapPaneToolbar"), Locale.ENGLISH);
+	
+	public static String R(String key, Object... values) {
+		return RESOURCE.getString(key, values);
+	}
+
+	/** Constant for the tool "Panning" (10). */
+	public static final int TOOL_PAN = 10;
+	/** Constant for the tool "Info" (20). */
+	public static final int TOOL_INFO = 20;
+	public static final int SEPERATOR0 = 99;
+
+	/** Constant for the tool "Zoom In" (110). */
+	public static final int TOOL_ZOOMIN = 110;
+	/** Constant for the tool "Zoom Out" (120). */
+	public static final int TOOL_ZOOMOUT = 120;
+	/** Constant for the action "Zoom back" (130). */
+	public static final int ACTION_ZOOM_BACK = 130;
+	/** Constant for the action "Zoom forward" (140). */
+	public static final int ACTION_ZOOM_FORWARD = 140;
+	public static final int SEPERATOR1 = 199;
+
+	/**
+	 * Constant for the tool "Selection Reset" which clears the selection (240).
+	 */
+	public static final int TOOL_SELECTION_CLEAR = 240;
+
+	/**
+	 * Constant for the tool "Select" which sets the Selection to the selected
+	 * features (210).
+	 */
+	public static final int TOOL_SELECTION_SET = 210;
+	/**
+	 * Constant for the tool "Selection add" which adds the features to the
+	 * Selection (220).
+	 */
+	public static final int TOOL_SELECTION_ADD = 220;
+	/**
+	 * Constant for the tool "Selection subtract" which removes the selected
+	 * features from the selection (230).
+	 */
+	public static final int TOOL_SELECTION_REMOVE = 230;
+
+	/** Tool currently selected */
+	protected int selectedTool = TOOL_ZOOMIN;
+
+	/** Holds the tool buttons of the tool bar. */
+	protected SortedMap<Integer, JComponent> toolAndActionButtons = null;
+	/** Controls that only one tool button is activated. */
+	protected ButtonGroup toolButtonGroup = null;
+
+	// SK: Musste ich ändern damit man Tools und Actions in der Reihenfolge
+	// mischen kann.
+	// /** Holds the action buttons of the bar. */
+	// protected SortedMap<Integer, JButton> actionButtons = null;
+
+	/** Holds the {@link JMapPane} this tool bar controls. */
+	protected JMapPane mapPane = null;
+
+	/**
+	 * A List to remember the last Envelopes that have been watched. Used for
+	 * the zoomBack- and zoomForwardButtons *
+	 */
+	protected ArrayList<Envelope> lastZooms = new ArrayList<Envelope>();
+	/** Holds the index to the current element in {@link #lastZooms}. */
+	protected int zoomBackIndex = 0;
+
+	/** Listener to sniff the zoom actions on the map. */
+	protected JMapPaneListener mapPaneListener = null;
+
+	protected boolean zoomBackForwardButtonInAction;
+
+	/**
+	 * Creates a new toolbar. Notice: This toolbar does nothing until
+	 * {@link #setMapPane(JMapPane)} is called!
+	 */
+	public MapPaneToolBar() {
+		this(null);
+	}
+
+	/**
+	 * Creates a new tool bar.
+	 * 
+	 * @param mapPane
+	 *            {@link JMapPane} the tool bar controls
+	 */
+	public MapPaneToolBar(JMapPane mapPane) {
+		super("Control the map", JToolBar.HORIZONTAL);
+		this.toolAndActionButtons = new TreeMap<Integer, JComponent>();
+		this.toolButtonGroup = new ButtonGroup();
+		
+		// Create a Listener to listen to the zooms on the JMapPane
+		this.mapPaneListener = new JMapPaneListener() {
+			public void performMapPaneEvent(JMapPaneEvent e) {
+				if (!(e instanceof MapAreaChangedEvent))
+					return;
+
+				if (zoomBackForwardButtonInAction) {
+					zoomBackForwardButtonInAction = false;
+					return;
+				}
+
+				final MapAreaChangedEvent mapAreaChangedEvent = (MapAreaChangedEvent) e;
+				Envelope oldMapArea = mapAreaChangedEvent.getOldMapArea();
+				
+				final Envelope mapArea = mapAreaChangedEvent.getNewMapArea();
+				if (mapArea == null || mapArea.equals(oldMapArea) ) {
+					// If the MapArea didn't change... we don't want to register it as a zoom action.
+					return;
+				}
+				
+				if (lastZooms.size() == 0 && oldMapArea != null) {
+					lastZooms.add(oldMapArea);
+					zoomBackIndex = 1;
+				}
+				if (mapArea == null)
+					return;
+
+				if (lastZooms.size() > 0
+						&& mapArea.equals(lastZooms.get(lastZooms.size() - 1))) {
+					// LOGGER.debug("MapAreaChangedEvent ausgelassen bei der Zaehlung der Zoomschritt weil identisch");
+					return;
+				}
+
+				if (lastZooms.size() > 0)
+					while (zoomBackIndex < lastZooms.size())
+						lastZooms.remove(lastZooms.size() - 1);
+
+				lastZooms.add(mapArea);
+				zoomBackIndex = lastZooms.size();
+				setButtonEnabled(ACTION_ZOOM_BACK, lastZooms.size() > 1);
+				setButtonEnabled(ACTION_ZOOM_FORWARD, false);
+			}
+		};
+
+		setMapPane(mapPane);
+		setFloatable(false);
+		setRollover(true);
+
+		init();
+	}
+
+	/**
+	 * Sets the {@link JMapPane} controlled by this tool bar.
+	 * 
+	 * @param mapPane
+	 *            {@link JMapPane} to control (if {@code null} this tool bar
+	 *            controls NOTHING!)
+	 */
+	public void setMapPane(JMapPane mapPane) {
+		// Remove listener from old MapPane
+		if (this.mapPane != null)
+			this.mapPane.removeMapPaneListener(mapPaneListener);
+		this.mapPane = mapPane;
+		if (this.mapPane != null && mapPaneListener != null)
+			this.mapPane.addMapPaneListener(mapPaneListener);
+	}
+
+	/**
+	 * Calls {@link #initToolsAndActions()} and {@link #initActions()} and then
+	 * puts all tool buttons and all actions buttons to the tool bar.
+	 */
+	protected void init() {
+		initToolsAndActions();
+
+		addSeparator(SEPERATOR0, new JToolBar.Separator());
+		addSeparator(SEPERATOR1, new JToolBar.Separator());
+
+		initToolBar();
+	}
+
+	/**
+	 * Creates the tool buttons and action buttons and seperators, adds them to
+	 * {@link #toolAndActionButtons} and finally creates a button group for all
+	 * tools. So sub-classes which override this method should FIRST add their
+	 * new tool buttons to {@link #toolAndActionButtons} before calling {@code
+	 * super.initTools()}.
+	 */
+	protected void initToolsAndActions() {
+		// Panning
+		addTool(new MapPaneToolBarAction(TOOL_PAN, this, "", new ImageIcon(
+				MapView.class.getResource("resource/icons/pan.png")), R("MapPaneButtons.Pan.TT")), false);
+		// Info
+		addTool(new MapPaneToolBarAction(TOOL_INFO, this, "", new ImageIcon(
+				MapView.class.getResource("resource/icons/info.png")),R("MapPaneButtons.Info.TT")), false);
+
+		// Zoom in
+		addTool(new MapPaneToolBarAction(TOOL_ZOOMIN, this, "", new ImageIcon(
+				MapView.class.getResource("resource/icons/zoom_in.png")), R("MapPaneButtons.ZoomIn.TT")),
+				false);
+		// Zoom out
+		addTool(new MapPaneToolBarAction(TOOL_ZOOMOUT, this, "", new ImageIcon(
+				MapView.class.getResource("resource/icons/zoom_out.png")), R("MapPaneButtons.ZoomOut.TT")),
+				false);
+
+		// Action button to revert the last zoom
+		addAction(new MapPaneToolBarAction(ACTION_ZOOM_BACK, this, "",
+				new ImageIcon(MapView.class
+						.getResource("resource/icons/zoom_back.png")), R("MapPaneButtons.LastZoom.TT")), false);
+		setButtonEnabled(ACTION_ZOOM_BACK, false);
+
+		// Action button to redo the last zoom
+		addAction(new MapPaneToolBarAction(ACTION_ZOOM_FORWARD, this, "",
+				new ImageIcon(MapView.class
+						.getResource("resource/icons/zoom_forward.png")), R("MapPaneButtons.NextZoom.TT")),
+				false);
+		setButtonEnabled(ACTION_ZOOM_FORWARD, false);
+
+		// set the selected tool enabled
+		setSelectedTool(selectedTool);
+
+	}
+
+	/**
+	 * Clears the GUI of all components and adds all tool and action buttons to
+	 * the tool bar.
+	 */
+	public void initToolBar() {
+		setAlignmentY(1f);
+		removeAll();
+		// Separator to the left of the tool actions to start
+		// the tool buttons with the map (not with the coordinate grid)
+		Dimension dimension = new Dimension(49, 10);
+		addSeparator(dimension);
+		// Tool buttons
+		for (JComponent b : toolAndActionButtons.values())
+			add(b);
+
+		if (!toolAndActionButtons.containsKey(selectedTool)) {
+			/**
+			 * This might be a bit specific, but IF selection buttons are
+			 * available, select one of them.. if not, select the INFO tool.
+			 */
+
+			if (toolAndActionButtons.containsKey(TOOL_SELECTION_SET)) {
+				setSelectedTool(TOOL_SELECTION_SET);
+			} else if (toolAndActionButtons.containsKey(TOOL_INFO)) {
+				setSelectedTool(TOOL_INFO);
+			} else {
+				// TODO What to do now?!
+				setSelectedTool(null);
+			}
+
+		}
+		
+		revalidate();
+		repaint();
+	}
+
+	// Space between tool buttons and action buttons
+	// SK: Seperators are now als manages like actions and tools
+	// Dimension dimension2 = new Dimension( 10,10);
+	// this.addSeparator(dimension2);
+
+	// // Action buttons
+	// for (JButton b : actionButtons.values())
+	// add(b);
+	// }
+
+	/**
+	 * Performs the activation of a tool.
+	 * 
+	 * @param tool
+	 *            the tool to activate
+	 * @param e
+	 *            the event of the button
+	 */
+	public void performToolButton(int tool, ActionEvent e) {
+		if (mapPane == null)
+			return;
+
+		selectedTool = tool;
+
+		switch (tool) {
+		case TOOL_PAN:
+			// Set the mouse tool to "Panning"
+			mapPane.setWindowSelectionState(JMapPane.NONE);
+			mapPane.setState(JMapPane.PAN);
+			mapPane.setHighlight(false);
+			mapPane.setNormalCursor(SwingUtil.PAN_CURSOR);
+			break;
+		case TOOL_INFO:
+			// Set the mouse tool to "Info"
+			mapPane.setWindowSelectionState(JMapPane.NONE);
+			mapPane.setState(JMapPane.SELECT_TOP); // Why not:
+			// JMapPane.SELECT_TOP_ONEONLY
+			mapPane.setHighlight(false);// SK: Was true, but since it not works
+			// properly removed it to save
+			// performance
+			mapPane.setNormalCursor(SwingUtil.CROSSHAIR_CURSOR);
+			break;
+		case TOOL_ZOOMIN:
+			// Set the mouse tool to "Zoom in"
+			mapPane.setWindowSelectionState(JMapPane.ZOOM_IN);
+			mapPane.setState(JMapPane.ZOOM_IN);
+			mapPane.setHighlight(false);
+			mapPane.setNormalCursor(SwingUtil.ZOOMIN_CURSOR);
+			break;
+		case TOOL_ZOOMOUT:
+			// Set the mouse tool to "Zoom out"
+			mapPane.setWindowSelectionState(JMapPane.NONE);
+			mapPane.setState(JMapPane.ZOOM_OUT);
+			mapPane.setHighlight(false);
+			mapPane.setNormalCursor(SwingUtil.ZOOMOUT_CURSOR);
+			break;
+		default:
+			// Set map actions to default
+			mapPane.setWindowSelectionState(JMapPane.NONE);
+			mapPane.setState(JMapPane.NONE);
+			mapPane.setHighlight(false);
+			mapPane.setNormalCursor(null);
+			break;
+		}
+		mapPane.updateCursor();
+	}
+
+	/**
+	 * @param id
+	 *            The ID of the Component to remove. The change will not be
+	 *            visible until {@link #initToolBar()} is called.
+	 * @return <code>null</code> or the component that has been removed.
+	 */
+	public JComponent removeId(int id) {
+		return toolAndActionButtons.remove(id);
+	}
+
+	/**
+	 * Performs the action of an action button.
+	 * 
+	 * @param tool
+	 *            the action
+	 * @param e
+	 *            the event of the button
+	 */
+	protected void performActionButton(int action, ActionEvent e) {
+		if (mapPane == null)
+			return;
+
+		// Perform the action "Zoom back": Revert the last zoom
+		if (action == ACTION_ZOOM_BACK) {
+			if (zoomBackIndex <= 1)
+				return;
+
+			zoomBackForwardButtonInAction = true;
+			zoomBackIndex--;
+			getButton(ACTION_ZOOM_FORWARD).setEnabled(true);
+			getButton(ACTION_ZOOM_BACK).setEnabled(zoomBackIndex > 1);
+
+			mapPane.setMapArea(lastZooms.get(zoomBackIndex - 1));
+			mapPane.refresh();
+		}
+
+		// Perform the action "Zoom forward": Re-do the last zoom
+		if (action == ACTION_ZOOM_FORWARD) {
+			if (zoomBackIndex < lastZooms.size()) {
+				zoomBackForwardButtonInAction = true;
+				zoomBackIndex++;
+				getButton(ACTION_ZOOM_BACK).setEnabled(true);
+				getButton(ACTION_ZOOM_FORWARD).setEnabled(
+						zoomBackIndex < lastZooms.size());
+
+				mapPane.setMapArea(lastZooms.get(zoomBackIndex - 1));
+				mapPane.refresh();
+			}
+		}
+	}
+
+	/**
+	 * Adds a tool to the tool bar. Does nothing if a tool or action with the
+	 * specified ID already exists!
+	 * 
+	 * @param buttonAction
+	 *            action for the toggle button
+	 * @param resetToolBar
+	 *            indicates whether the toolbar GUI is reset after adding the
+	 *            button (if adding several actions it useful only to reset the
+	 *            GUI for the last added tool)
+	 */
+	public void addTool(MapPaneToolBarAction buttonAction, boolean resetToolBar) {
+		if (isButtonIDUsed(buttonAction.getID())) {
+			LOGGER
+					.warn("addTool(.) ignored because ID already used for tool or action: "
+							+ buttonAction.getID());
+			return;
+		}
+		JToggleButton button = new JToggleButton(buttonAction);
+		button.setBorder(BorderFactory.createRaisedBevelBorder());
+		toolButtonGroup.add(button);
+		toolAndActionButtons.put(buttonAction.getID(), button);
+		if (resetToolBar)
+			initToolBar();
+	}
+
+	/**
+	 * Adds a tool to the tool bar and resets the toolbar GUI.
+	 * 
+	 * @param buttonAction
+	 *            action for the toggle button
+	 */
+	public void addTool(MapPaneToolBarAction buttonAction) {
+		addTool(buttonAction, true);
+	}
+
+	/**
+	 * Adds an action to the tool bar. Does nothing if a tool or action with the
+	 * specified ID already exists!
+	 * 
+	 * @param buttonAction
+	 *            action for the button
+	 * @param resetToolBar
+	 *            indicates whether the toolbar GUI is reset after adding the
+	 *            button (if adding several actions it useful only to reset the
+	 *            GUI for the last added tool)
+	 */
+	public void addAction(MapPaneToolBarAction buttonAction,
+			boolean resetToolBar) {
+		if (isButtonIDUsed(buttonAction.getID())) {
+			LOGGER
+					.warn("addAction(.) ignored because ID already used for tool or action: "
+							+ buttonAction.getID());
+			return;
+		}
+		JButton button = new JButton(buttonAction);
+		button.setBorder(BorderFactory.createRaisedBevelBorder());
+		toolAndActionButtons.put(buttonAction.getID(), button);
+		if (resetToolBar)
+			initToolBar();
+	}
+
+	public void addSeparator(int id, Separator separator) {
+		if (isButtonIDUsed(id)) {
+			LOGGER
+					.warn("addSeparator(.) ignored because ID already used for tool or action. ");
+			return;
+		}
+		toolAndActionButtons.put(id, separator);
+	}
+
+	/**
+	 * Adds an action to the tool bar and resets the toolbar GUI.
+	 * 
+	 * @param buttonAction
+	 *            action for the toggle button
+	 */
+	public void addAction(MapPaneToolBarAction buttonAction) {
+		addAction(buttonAction, true);
+	}
+
+	/**
+	 * Returns the button for a specific tool or action.
+	 * 
+	 * @param id
+	 *            the constant for any button in the {@link MapPaneToolBar}
+	 * @return a {@link JButton} if {@code id} specifies an
+	 *         {@linkplain #getActionButton(int) action button} or
+	 *         {@link JToogleButton} if {@code id} specifies a
+	 *         {@linkplain #getToolButton(int) tool button}
+	 */
+	public AbstractButton getButton(int id) {
+		AbstractButton button = (AbstractButton) toolAndActionButtons.get(id);
+		if (button == null)
+			LOGGER.warn("Unknown tool or action ID: " + id);
+		return button;
+	}
+
+	/**
+	 * Returns the button for a specific tool.
+	 * 
+	 * @param tool
+	 *            the constant for a tool
+	 */
+	public JToggleButton getToolButton(int tool) {
+		AbstractButton button = getButton(tool);
+		if (button != null && !(button instanceof JToggleButton)) {
+			LOGGER.warn("ID specifies no tool: " + tool);
+			button = null;
+		}
+		return (JToggleButton) button;
+	}
+
+	/**
+	 * Returns the button for a specific action.
+	 * 
+	 * @param action
+	 *            the constant an action
+	 */
+	public JButton getActionButton(int action) {
+		AbstractButton button = getButton(action);
+		if (button != null && !(button instanceof JButton)) {
+			LOGGER.warn("ID specifies no action: " + action);
+			button = null;
+		}
+		return (JButton) button;
+
+	}
+
+	/**
+	 * Sets the selected tool.
+	 * 
+	 * @param tool
+	 *            ID of the tool
+	 */
+	public void setSelectedTool(Integer tool) {
+		if (tool == null)
+			toolButtonGroup.setUnselected();
+
+		JToggleButton button = getToolButton(tool);
+		if (button == null)
+			return;
+		button.setSelected(true);
+		button.getAction().actionPerformed(null);
+
+		selectedTool = tool;
+	}
+
+	/**
+	 * Returns the selected tool.
+	 * 
+	 * @return -1 if no tool is active
+	 */
+	public int getSelectedTool() {
+		if (toolButtonGroup.getSelectedButton() == null)
+			return -1;
+		return selectedTool;
+	}
+
+	/**
+	 * Sets whether a tool or action is activated or not. The visible property
+	 * of the button is not affected.
+	 * 
+	 * @param id
+	 *            tool or actionID
+	 * @param enabled
+	 *            if {@code true} the tool becomes available
+	 */
+	public void setButtonEnabled(int id, boolean enabled) {
+		AbstractButton button = getButton(id);
+		if (button == null)
+			return;
+		button.setEnabled(enabled);
+	}
+
+	/**
+	 * Sets whether a tool or action is activated or not.
+	 * 
+	 * @param id
+	 *            tool or actionID
+	 * @param enabled
+	 *            if {@code true} the tool becomes available
+	 * @param hideOnDisable
+	 *            if {@code true} the button is also hidden if {@code enabled}
+	 *            is {@code false}
+	 */
+	public void setButtonEnabled(int id, boolean enabled, boolean hideOnDisable) {
+		AbstractButton button = getButton(id);
+		if (button == null)
+			return;
+		button.setEnabled(enabled);
+		// if button is enabled, it becomes visible anyway
+		// if button is disabled and the "hide" option is set, it is also hidden
+		if (enabled)
+			button.setVisible(true);
+		else
+			button.setVisible(!hideOnDisable);
+	}
+
+	/**
+	 * Checks whether a ID is already used for a tool or action.
+	 * 
+	 * @param tool
+	 *            tool ID
+	 */
+	public boolean isButtonIDUsed(int id) {
+		return toolAndActionButtons.get(id) != null;
+	}
+
+	/**
+	 * Checks whether a tool is activated.
+	 * 
+	 * @param tool
+	 *            tool ID
+	 * @return {@code false} if an unknown ID is specified
+	 */
+	public boolean isButtonEnabled(int id) {
+		AbstractButton button = getButton(id);
+		if (button != null)
+			return button.isEnabled();
+		return false;
+	}
+
+	/**
+	 * Sets the activation for all tools.
+	 * 
+	 * @param enabled
+	 *            if {@code true} all tools becomes available
+	 * @param hideOnDisable
+	 *            if {@code true} the buttons are also hidden if {@code enabled}
+	 *            is {@code false}
+	 */
+	public void setAllToolsEnabled(boolean enabled, boolean hideOnDisable) {
+		for (int tool : toolAndActionButtons.keySet())
+			setButtonEnabled(tool, enabled, hideOnDisable);
+	}
+
+	/**
+	 * Sets the activation for all actions.
+	 * 
+	 * @param enabled
+	 *            if {@code true} all actions becomes available
+	 * @param hideOnDisable
+	 *            if {@code true} the buttons are also hidden if {@code enabled}
+	 *            is {@code false}
+	 */
+	public void setAllActionsEnabled(boolean enabled, boolean hideOnDisable) {
+		for (int id : toolAndActionButtons.keySet()) {
+			if (toolAndActionButtons.get(id) instanceof JButton) {
+				setButtonEnabled(id, enabled, hideOnDisable);
+			}
+		}
+
+	}
+
+	/**
+	 * Returns the maximum ID of tools.
+	 */
+	public int getMaxToolID() {
+		return toolAndActionButtons.lastKey();
+	}
+
+	/**
+	 * Returns the minimum ID of tools.
+	 */
+	public int getMinToolID() {
+		return toolAndActionButtons.firstKey();
+	}
+
+	/**
+	 * Extends the {@link AbstractAction} with maintaining an ID and the
+	 * {@link MapPaneToolBar} the actions controls. Additionally this class
+	 * automatically calls
+	 * {@link MapPaneToolBar#performToolButton(int, ActionEvent)} or
+	 * {@link MapPaneToolBar#performActionButton(int, ActionEvent)} depending on
+	 * whether the action is added via
+	 * {@link MapPaneToolBar#addTool(MapPaneToolBarAction)} or
+	 * {@link MapPaneToolBar#addAction(MapPaneToolBarAction)}.
+	 * 
+	 * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+	 *         (University of Bonn/Germany)
+	 */
+	public static class MapPaneToolBarAction extends AbstractAction {
+		/** The ID of the action */
+		protected int id = -1;
+		/** The tool bar, this action is made for. */
+		protected MapPaneToolBar toolBar = null;
+
+		/**
+		 * Creates a new action with a dummy description and no icon.
+		 * 
+		 * @param id
+		 *            unique ID for the action
+		 * @param toolBar
+		 *            toolbar this action is made for
+		 */
+		public MapPaneToolBarAction(int id, MapPaneToolBar toolBar) {
+			this(id, toolBar, "" + id);
+		}
+
+		/**
+		 * Creates a new action without an icon.
+		 * 
+		 * @param id
+		 *            unique ID for the action
+		 * @param toolBar
+		 *            toolbar this action is made for
+		 * @param name
+		 *            description used for buttons or menus
+		 */
+		public MapPaneToolBarAction(int id, MapPaneToolBar toolBar, String name) {
+			this(id, toolBar, name, null);
+		}
+
+		/**
+		 * Creates a new action.
+		 * 
+		 * @param id
+		 *            unique ID for the action
+		 * @param toolBar
+		 *            toolbar this action is made for
+		 * @param name
+		 *            description used for buttons or menus
+		 * @param icon
+		 *            icon used for buttons or menus
+		 */
+		public MapPaneToolBarAction(int id, MapPaneToolBar toolBar,
+				String name, Icon icon) {
+			this (id, toolBar, name, icon, null);
+		}
+		
+		/**
+		 * Creates a new action.
+		 * 
+		 * @param id
+		 *            unique ID for the action
+		 * @param toolBar
+		 *            The {@link MapPaneToolBar} this action is made for
+		 * @param name
+		 *            description used for buttons or menus
+		 * @param icon
+		 *            icon used for buttons or menus
+		 * @param toolTip
+		 *            Tooltip to use for the button or menu
+		 */
+		public MapPaneToolBarAction(int id, MapPaneToolBar toolBar,
+				String name, Icon icon, String toolTip) {
+			super(name, icon);
+			
+			if (toolTip != null && !toolTip.trim().isEmpty()){
+				putValue(Action.SHORT_DESCRIPTION, toolTip);
+			}
+			
+			this.id = id;
+			this.toolBar = toolBar;
+		}
+
+		/**
+		 * Calls {@link MapPaneToolBar#performToolButton(int, ActionEvent)} or
+		 * {@link MapPaneToolBar#performActionButton(int, ActionEvent)}
+		 * depending on whether the action is added to the toolbar via
+		 * {@link MapPaneToolBar#addTool(MapPaneToolBarAction)} or
+		 * {@link MapPaneToolBar#addAction(MapPaneToolBarAction)}.
+		 */
+		public void actionPerformed(ActionEvent e) {
+			if (toolBar.toolAndActionButtons.get(id) instanceof JToggleButton)
+				toolBar.performToolButton(id, e);
+			else if (toolBar.toolAndActionButtons.get(id) instanceof JButton)
+				toolBar.performActionButton(id, e);
+		}
+
+		/**
+		 * Returns the (unique) id of this action.
+		 * 
+		 * @return
+		 */
+		public int getID() {
+			return id;
+		}
+	}
+	
+	  /**
+	   * Nuetzlich wenn die Componente gedruckt (z.B. wenn ein Screenshot gemacht wird) wird. Dann werden wird der
+	   * Hintergrund auf WEISS gesetzt.
+	   *
+	   * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	   *         Kr&uuml;ger</a>
+	   */
+	  @Override
+	  public void print(Graphics g) {
+	      Color orig = getBackground();
+	      setBackground(Color.WHITE);
+	      // wrap in try/finally so that we always restore the state
+	      try {
+	          super.print(g);
+	      } finally {
+	          setBackground(orig);
+	      }
+	  }
+}

Modified: trunk/src/skrueger/geotools/MapView.java
===================================================================
--- trunk/src/skrueger/geotools/MapView.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/MapView.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,211 +1,240 @@
-package skrueger.geotools;
-
-import java.awt.BorderLayout;
-import java.awt.Component;
-
-import javax.swing.BorderFactory;
-import javax.swing.JComponent;
-import javax.swing.JPanel;
-import javax.swing.JSplitPane;
-
-import org.apache.log4j.Logger;
-import org.geotools.renderer.lite.StreamingRenderer;
-import org.geotools.renderer.shape.TransitionShapefileRenderer;
-
-import schmitzm.geotools.gui.GeoMapPane;
-import schmitzm.geotools.gui.JMapPane;
-import schmitzm.geotools.gui.MapContextControlPane;
-import schmitzm.geotools.gui.MapPaneStatusBar;
-import schmitzm.geotools.styling.ColorMapManager;
-
-/**
- * Achtung! Dieser code ist verwuestet TODO DOKU und initialize schöner machen.
- * SK
- */
-public class MapView extends JPanel {
-	private static final Logger LOGGER = Logger.getLogger(MapView.class);
-
-	private final JSplitPane splitPane = new JSplitPane(
-			JSplitPane.HORIZONTAL_SPLIT);
-
-	protected MapPaneStatusBar statusBar = null;
-
-	/**
-	 * Komponente, in der die Karten, der Massstab und das Koordinaten-Raster
-	 * dargestellt werden.
-	 */
-
-	protected final GeoMapPane geoMapPane = new GeoMapPane();
-
-	private MapPaneToolBar jToolBar;
-
-	/**
-	 * Creates a new {@link MapView}. A {@link MapView} is a combination of a
-	 * {@link GeoMapPane}, a {@link MapContextManagerInterface} on the left, and
-	 * some buttons floating over the {@link JMapPane}
-	 */
-	public MapView(Component parentGui, MapPaneToolBar toolBar) {
-		super(new BorderLayout());
-		// Call initialize() by yourself afterwards.
-		// Needed because variables for the overwritten methods
-		// are not yet set.
-		getGeoMapPane().getMapPane().setWaitCursorComponent(parentGui);
-		if (toolBar == null)
-			toolBar = new MapPaneToolBar(getMapPane());
-		jToolBar = toolBar;
-	}
-
-	/**
-	 * Creates a new {@link MapView}. A {@link MapView} is a combination of a
-	 * {@link GeoMapPane}, a {@link MapContextManagerInterface} on the left, and
-	 * some buttons floating over the {@link JMapPane}
-	 */
-	public MapView(Component parentGui) {
-		this(parentGui, null);
-	}
-
-	/**
-	 * This routine creates the main components of the GUI: The left Side and
-	 * the map on the right side.<br/>
-	 * Calls #getSidePanel() which can be overwritten (call super!).<br/>
-	 * 
-	 * This method initialized the variables {@link #statusBar} and
-	 * {@link #splitPane}
-	 * 
-	 * @see #adjustSizeOfGeoMapPane()
-	 */
-	public void initialize() {
-		// horizontales SplitPane initialisieren
-
-		// Status-Line to show Coordinates and Rastervalues.
-		statusBar = new MapPaneStatusBar(getGeoMapPane().getMapPane());
-		statusBar.setBorder(BorderFactory.createCompoundBorder(BorderFactory
-				.createLoweredBevelBorder(), BorderFactory.createEmptyBorder(2,
-				5, 2, 5)));
-		this.add(statusBar, BorderLayout.SOUTH);
-
-		/**
-		 * The layout of the split pane can be configured in the atlas.
-		 * setDividerLocation(-1); has no effect here because the component is
-		 * not visible yet.
-		 */
-		getSplitPane().setDividerSize(5);
-
-		getSplitPane().setResizeWeight(0.0);
-		getSplitPane().add(getSidePane());
-
-		/***********************************************************************
-		 * To the right side we now add a JPanel that consists of a toolbar and
-		 * a gmp
-		 */
-		JPanel newRight = new JPanel(new BorderLayout());
-		newRight.add(getToolBar(), BorderLayout.NORTH);
-		newRight.add(getGeoMapPane(), BorderLayout.CENTER);
-		getSplitPane().add(newRight);
-
-		this.add(getSplitPane(), BorderLayout.CENTER);
-	}
-
-	/**
-	 * Returns the tool bar which controls the active mouse actions on the map.
-	 * 
-	 * @return
-	 */
-	public MapPaneToolBar getToolBar() {
-		return jToolBar;
-	}
-
-	/**
-	 * Returns the split pane which divides the layer list from the map panel.
-	 */
-	public JSplitPane getSplitPane() {
-		return splitPane;
-	}
-
-	/**
-	 * Sets the active tool. Simply calls
-	 * {@link MapPaneToolBar#setSelectedTool(Integer)}.
-	 * 
-	 * @param tool
-	 *            One of {@link #TOOL_INFO}, {@link #TOOL_PAN} .. constants
-	 */
-	public void setSelectedTool(Integer tool) {
-		jToolBar.setSelectedTool(tool);
-	}
-
-	/**
-	 * Sets whether a tool is activated or not. Simply calls
-	 * {@link MapPaneToolBar#setButtonEnabled(int, boolean, boolean)}.
-	 * 
-	 * @param tool
-	 *            tool ID
-	 * @param enabled
-	 *            if {@code true} the tool becomes available
-	 * @param hideOnDisable
-	 *            if {@code true} the button is also hidden if {@code enabled}
-	 *            is {@code false}
-	 */
-	public void setToolEnabled(Integer tool, boolean enabled,
-			boolean hideOnDisable) {
-		jToolBar.setButtonEnabled(tool, enabled, hideOnDisable);
-	}
-
-	/**
-	 * Sets the activation for all tools. Simply calls
-	 * {@link MapPaneToolBar#setAllToolsEnabled(boolean, boolean)}.
-	 * 
-	 * @param enabled
-	 *            if {@code true} all tool becomes available
-	 * @param hideOnDisable
-	 *            if {@code true} the buttons are also hidden if {@code enabled}
-	 *            is {@code false}
-	 */
-	public void setAllToolsEnabled(boolean enabled, boolean hideOnDisable) {
-		jToolBar.setAllToolsEnabled(enabled, hideOnDisable);
-	}
-
-	/**
-	 * Checks whether a tool is activated. Simply calls
-	 * {@link MapPaneToolBar#isButtonEnabled(Integer)}.
-	 * 
-	 * @param tool
-	 *            tool ID
-	 * @return {@code false} if an unknown ID is specified
-	 */
-	public boolean isToolEnabled(Integer tool) {
-		return jToolBar.isButtonEnabled(tool);
-	}
-
-	/**
-	 * called by initialize() to fill the left of the XULUMapView Supposed to be
-	 * overwritten by AtlasMapView or DesignMapView
-	 */
-	public JComponent getSidePane() {
-		return new MapContextControlPane(getGeoMapPane().getMapPane(),
-				new ColorMapManager());
-	}
-
-	/**
-	 * Liefert die Status-Zeile, in der die Koordinaten und Raster-Werte
-	 * angezeigt werden.
-	 */
-	public MapPaneStatusBar getStatusBar() {
-		return this.statusBar;
-	}
-
-	/**
-	 * Liefert den Karten-Bereich der Komponente.
-	 */
-	public final JMapPane getMapPane() {
-		return getGeoMapPane().getMapPane();
-	}
-
-	public GeoMapPane getGeoMapPane() {
-		return geoMapPane;
-	}
-
-	public int getSelectedTool() {
-		return jToolBar.getSelectedTool();
-	}
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package skrueger.geotools;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+
+import javax.swing.BorderFactory;
+import javax.swing.JComponent;
+import javax.swing.JPanel;
+import javax.swing.JSplitPane;
+
+import org.apache.log4j.Logger;
+import org.geotools.renderer.lite.StreamingRenderer;
+import org.geotools.renderer.shape.TransitionShapefileRenderer;
+
+import schmitzm.geotools.gui.GeoMapPane;
+import schmitzm.geotools.gui.JMapPane;
+import schmitzm.geotools.gui.MapContextControlPane;
+import schmitzm.geotools.gui.MapPaneStatusBar;
+import schmitzm.geotools.styling.ColorMapManager;
+
+/**
+ * Achtung! Dieser code ist verwuestet TODO DOKU und initialize schöner machen.
+ * SK
+ */
+public class MapView extends JPanel {
+	private static final Logger LOGGER = Logger.getLogger(MapView.class);
+
+	private final JSplitPane splitPane = new JSplitPane(
+			JSplitPane.HORIZONTAL_SPLIT);
+
+	protected MapPaneStatusBar statusBar = null;
+
+	/**
+	 * Komponente, in der die Karten, der Massstab und das Koordinaten-Raster
+	 * dargestellt werden.
+	 */
+
+	protected final GeoMapPane geoMapPane = new GeoMapPane();
+
+	private MapPaneToolBar jToolBar;
+
+	/**
+	 * Creates a new {@link MapView}. A {@link MapView} is a combination of a
+	 * {@link GeoMapPane}, a {@link MapContextManagerInterface} on the left, and
+	 * some buttons floating over the {@link JMapPane}
+	 */
+	public MapView(Component parentGui, MapPaneToolBar toolBar) {
+		super(new BorderLayout());
+		// Call initialize() by yourself afterwards.
+		// Needed because variables for the overwritten methods
+		// are not yet set.
+		getGeoMapPane().getMapPane().setWaitCursorComponent(parentGui);
+		if (toolBar == null)
+			toolBar = new MapPaneToolBar(getMapPane());
+		jToolBar = toolBar;
+	}
+
+	/**
+	 * Creates a new {@link MapView}. A {@link MapView} is a combination of a
+	 * {@link GeoMapPane}, a {@link MapContextManagerInterface} on the left, and
+	 * some buttons floating over the {@link JMapPane}
+	 */
+	public MapView(Component parentGui) {
+		this(parentGui, null);
+	}
+
+	/**
+	 * This routine creates the main components of the GUI: The left Side and
+	 * the map on the right side.<br/>
+	 * Calls #getSidePanel() which can be overwritten (call super!).<br/>
+	 * 
+	 * This method initialized the variables {@link #statusBar} and
+	 * {@link #splitPane}
+	 * 
+	 * @see #adjustSizeOfGeoMapPane()
+	 */
+	public void initialize() {
+		// horizontales SplitPane initialisieren
+
+		// Status-Line to show Coordinates and Rastervalues.
+		statusBar = new MapPaneStatusBar(getGeoMapPane().getMapPane());
+		statusBar.setBorder(BorderFactory.createCompoundBorder(BorderFactory
+				.createLoweredBevelBorder(), BorderFactory.createEmptyBorder(2,
+				5, 2, 5)));
+		this.add(statusBar, BorderLayout.SOUTH);
+
+		/**
+		 * The layout of the split pane can be configured in the atlas.
+		 * setDividerLocation(-1); has no effect here because the component is
+		 * not visible yet.
+		 */
+		getSplitPane().setDividerSize(5);
+
+		getSplitPane().setResizeWeight(0.0);
+		getSplitPane().add(getSidePane());
+
+		/***********************************************************************
+		 * To the right side we now add a JPanel that consists of a toolbar and
+		 * a gmp
+		 */
+		JPanel newRight = new JPanel(new BorderLayout());
+		newRight.add(getToolBar(), BorderLayout.NORTH);
+		newRight.add(getGeoMapPane(), BorderLayout.CENTER);
+		getSplitPane().add(newRight);
+
+		this.add(getSplitPane(), BorderLayout.CENTER);
+	}
+
+	/**
+	 * Returns the tool bar which controls the active mouse actions on the map.
+	 * 
+	 * @return
+	 */
+	public MapPaneToolBar getToolBar() {
+		return jToolBar;
+	}
+
+	/**
+	 * Returns the split pane which divides the layer list from the map panel.
+	 */
+	public JSplitPane getSplitPane() {
+		return splitPane;
+	}
+
+	/**
+	 * Sets the active tool. Simply calls
+	 * {@link MapPaneToolBar#setSelectedTool(Integer)}.
+	 * 
+	 * @param tool
+	 *            One of {@link #TOOL_INFO}, {@link #TOOL_PAN} .. constants
+	 */
+	public void setSelectedTool(Integer tool) {
+		jToolBar.setSelectedTool(tool);
+	}
+
+	/**
+	 * Sets whether a tool is activated or not. Simply calls
+	 * {@link MapPaneToolBar#setButtonEnabled(int, boolean, boolean)}.
+	 * 
+	 * @param tool
+	 *            tool ID
+	 * @param enabled
+	 *            if {@code true} the tool becomes available
+	 * @param hideOnDisable
+	 *            if {@code true} the button is also hidden if {@code enabled}
+	 *            is {@code false}
+	 */
+	public void setToolEnabled(Integer tool, boolean enabled,
+			boolean hideOnDisable) {
+		jToolBar.setButtonEnabled(tool, enabled, hideOnDisable);
+	}
+
+	/**
+	 * Sets the activation for all tools. Simply calls
+	 * {@link MapPaneToolBar#setAllToolsEnabled(boolean, boolean)}.
+	 * 
+	 * @param enabled
+	 *            if {@code true} all tool becomes available
+	 * @param hideOnDisable
+	 *            if {@code true} the buttons are also hidden if {@code enabled}
+	 *            is {@code false}
+	 */
+	public void setAllToolsEnabled(boolean enabled, boolean hideOnDisable) {
+		jToolBar.setAllToolsEnabled(enabled, hideOnDisable);
+	}
+
+	/**
+	 * Checks whether a tool is activated. Simply calls
+	 * {@link MapPaneToolBar#isButtonEnabled(Integer)}.
+	 * 
+	 * @param tool
+	 *            tool ID
+	 * @return {@code false} if an unknown ID is specified
+	 */
+	public boolean isToolEnabled(Integer tool) {
+		return jToolBar.isButtonEnabled(tool);
+	}
+
+	/**
+	 * called by initialize() to fill the left of the XULUMapView Supposed to be
+	 * overwritten by AtlasMapView or DesignMapView
+	 */
+	public JComponent getSidePane() {
+		return new MapContextControlPane(getGeoMapPane().getMapPane(),
+				new ColorMapManager());
+	}
+
+	/**
+	 * Liefert die Status-Zeile, in der die Koordinaten und Raster-Werte
+	 * angezeigt werden.
+	 */
+	public MapPaneStatusBar getStatusBar() {
+		return this.statusBar;
+	}
+
+	/**
+	 * Liefert den Karten-Bereich der Komponente.
+	 */
+	public final JMapPane getMapPane() {
+		return getGeoMapPane().getMapPane();
+	}
+
+	public GeoMapPane getGeoMapPane() {
+		return geoMapPane;
+	}
+
+	public int getSelectedTool() {
+		return jToolBar.getSelectedTool();
+	}
+
+}

Modified: trunk/src/skrueger/geotools/StyledFS.java
===================================================================
--- trunk/src/skrueger/geotools/StyledFS.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/StyledFS.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,258 +1,287 @@
-package skrueger.geotools;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.net.URL;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Random;
-
-import javax.swing.ImageIcon;
-import javax.swing.JPanel;
-
-import org.apache.log4j.Logger;
-import org.geotools.data.FeatureSource;
-import org.geotools.feature.AttributeType;
-import org.geotools.feature.FeatureCollection;
-import org.geotools.styling.Style;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-
-import schmitzm.geotools.styling.StylingUtil;
-import skrueger.AttributeMetaData;
-import skrueger.i8n.Translation;
-
-import com.vividsolutions.jts.geom.Envelope;
-
-/**
- * This class enables a non Atlas context to use the Atlas LayerPanel
- * {@link JPanel} as a {@link MapContextManagerInterface}
- * 
- * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
- */
-public class StyledFS implements StyledFeatureSourceInterface {
-	private static final Logger LOGGER = Logger.getLogger(StyledFS.class);
-
-	private final FeatureSource fs;
-
-	/**
-	 * A unique ID which identifies the Layer in the Atlas. It's more important
-	 * than it should be ;-)
-	 */
-	private String id;
-
-	private Style style;
-
-	private Translation title;
-
-	private Translation desc;
-
-	private File sldFile;
-
-	private HashMap<Integer, AttributeMetaData> map;
-
-	/**
-	 * This class enables a non Atlas context to use the Atlas LayerPanel
-	 * {@link JPanel} as a {@link MapContextManagerInterface}
-	 * 
-	 * @param fs
-	 *            {@link FeatureSource} that is beeing styled.
-	 * 
-	 * @param sldFile
-	 *            may be <code>null</code>. Otherwise the SLD {@link File} to
-	 *            import and associate with this {@link StyledFS}
-	 */
-	public StyledFS(FeatureSource fs, File sldFile) {
-
-		this.fs = fs;
-		id = StyledFS.class.getSimpleName()
-				+ new Random(new Date().getTime()).nextInt(10000000);
-
-		this.sldFile = sldFile;
-
-		if ((sldFile != null) && (sldFile.exists())) {
-			try {
-				style = StylingUtil.loadSLD(sldFile)[0];
-			} catch (FileNotFoundException e) {
-				LOGGER
-						.debug("The SLD file passed was empty. Leaving the Style untouched. (We are in the constructor.. so its null");
-			} catch (Exception e) {
-				LOGGER.warn("Reading SLD failed: " + sldFile, e);
-			}
-		}
-		title = new Translation();
-		title.fromOneLine(sldFile.getName());
-
-		desc = new Translation();
-		desc.fromOneLine(sldFile.getAbsolutePath());
-	}
-
-	public void dispose() {
-	}
-
-	/**
-	 * Returnes human readable {@link String} of the CRS natively used by this
-	 * {@link DpLayer}
-	 * 
-	 * If crs == null, it will call {@link #getGeoObject()}
-	 * 
-	 */
-	public String getCRSString() {
-		if (getCrs() == null)
-			return "CRS?";
-
-		return getCrs().getName().getCode();
-	}
-
-	public CoordinateReferenceSystem getCrs() {
-		return fs.getSchema().getDefaultGeometry().getCoordinateSystem();
-	}
-
-	public Translation getDesc() {
-		return desc;
-	}
-
-	public Envelope getEnvelope() {
-		try {
-			return fs.getBounds();
-		} catch (IOException e) {
-			e.printStackTrace();
-			return null;
-		}
-	}
-
-	public FeatureSource getGeoObject() {
-		return fs;
-	}
-
-	public String getId() {
-		return id;
-	}
-
-	public ImageIcon getImageIcon() {
-		return null;
-	}
-
-	public URL getInfoURL() {
-		return null;
-	}
-
-	public Translation getKeywords() {
-		return null;
-	}
-
-	public Style getStyle() {
-		return style;
-	}
-
-	public Translation getTitle() {
-		return title;
-	}
-
-	public boolean isDisposed() {
-		return false;
-	}
-
-	/**
-	 * If true, this layer will not be shown in the legend. Default = false
-	 */
-	/**
-	 * 
-	 * Killed by SK: 6. April 09: Ein Layer soll nicht generell auf
-	 * verstecken/nicht verstecken gestellt werden können. Das sind
-	 * Eigenschaften der Karte/MapContext, ebenso wie die Reihenfolge der Layer.
-	 * Im Atlas verwaltet deshalb nun die Klasse skrueger.atlas.Map welche Layer
-	 * nicht in der Legende auftauchen sollen. Meines Wissens hat keiner bisher
-	 * die Funktion genutzt.
-	 * 
-	 * // public boolean isHideInLegend() { // return false; // }
-	 */
-
-	public void setDesc(Translation dec) {
-		this.desc = dec;
-	}
-
-	public void setImageIcon(ImageIcon icon) {
-	}
-
-	public void setKeywords(Translation keywords) {
-	}
-
-	public void setStyle(Style style) {
-		this.style = style;
-
-	}
-
-	public void setTitle(Translation title) {
-		this.title = title;
-
-	}
-
-	public void uncache() {
-	}
-
-	/**
-	 * 
-	 */
-	public Map<Integer, AttributeMetaData> getAttributeMetaDataMap() {
-		if (map == null) {
-
-			map = new HashMap<Integer, AttributeMetaData>();
-
-			// Leaving out the first one, it will be the_geom
-			for (int i = 1; i < fs.getSchema().getAttributeCount(); i++) {
-				AttributeType att = fs.getSchema().getAttributeType(i);
-
-				AttributeMetaData attMetaData = new AttributeMetaData(i, att
-						.getLocalName());
-				map.put(i, attMetaData);
-			}
-		}
-		return map;
-	}
-
-	/**
-	 * @return The {@link File} where the SLD was loaded from or
-	 *         <code>null</code> if there didn't exist a {@link File}. 
-	 * 
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
-	 *         Kr&uuml;ger</a>
-	 */
-	public File getSldFile() {
-		return sldFile;
-	}
-
-	public void setSldFile(File sldFile) {
-		this.sldFile = sldFile;
-	}
-
-	/**
-	 * Returns the features of the {@link FeatureSource}.
-	 * 
-	 * @see {@link StyledFeaturesInterface}
-	 */
-	@Override
-	public FeatureCollection getFeatureCollection() {
-		FeatureCollection features;
-		try {
-			features = getGeoObject().getFeatures();
-		} catch (IOException e) {
-			throw new RuntimeException(
-					"Error getting the features of the  FeatureSource");
-		}
-		return features;
-	}
-
-	/**
-	 * Same as {@link #getGeoObject()} method, but complies to the
-	 * {@link StyledFeaturesInterface}
-	 * 
-	 * @see {@link StyledFeaturesInterface}
-	 */
-	@Override
-	public FeatureSource getFeatureSource() {
-		return getGeoObject();
-	}
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package skrueger.geotools;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.net.URL;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Random;
+
+import javax.swing.ImageIcon;
+import javax.swing.JPanel;
+
+import org.apache.log4j.Logger;
+import org.geotools.data.FeatureSource;
+import org.geotools.feature.AttributeType;
+import org.geotools.feature.FeatureCollection;
+import org.geotools.styling.Style;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+
+import schmitzm.geotools.styling.StylingUtil;
+import skrueger.AttributeMetaData;
+import skrueger.i8n.Translation;
+
+import com.vividsolutions.jts.geom.Envelope;
+
+/**
+ * This class enables a non Atlas context to use the Atlas LayerPanel
+ * {@link JPanel} as a {@link MapContextManagerInterface}
+ * 
+ * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
+ */
+public class StyledFS implements StyledFeatureSourceInterface {
+	private static final Logger LOGGER = Logger.getLogger(StyledFS.class);
+
+	private final FeatureSource fs;
+
+	/**
+	 * A unique ID which identifies the Layer in the Atlas. It's more important
+	 * than it should be ;-)
+	 */
+	private String id;
+
+	private Style style;
+
+	private Translation title;
+
+	private Translation desc;
+
+	private File sldFile;
+
+	private HashMap<Integer, AttributeMetaData> map;
+
+	/**
+	 * This class enables a non Atlas context to use the Atlas LayerPanel
+	 * {@link JPanel} as a {@link MapContextManagerInterface}
+	 * 
+	 * @param fs
+	 *            {@link FeatureSource} that is beeing styled.
+	 * 
+	 * @param sldFile
+	 *            may be <code>null</code>. Otherwise the SLD {@link File} to
+	 *            import and associate with this {@link StyledFS}
+	 */
+	public StyledFS(FeatureSource fs, File sldFile) {
+
+		this.fs = fs;
+		id = StyledFS.class.getSimpleName()
+				+ new Random(new Date().getTime()).nextInt(10000000);
+
+		this.sldFile = sldFile;
+
+		if ((sldFile != null) && (sldFile.exists())) {
+			try {
+				style = StylingUtil.loadSLD(sldFile)[0];
+			} catch (FileNotFoundException e) {
+				LOGGER
+						.debug("The SLD file passed was empty. Leaving the Style untouched. (We are in the constructor.. so its null");
+			} catch (Exception e) {
+				LOGGER.warn("Reading SLD failed: " + sldFile, e);
+			}
+		}
+		title = new Translation();
+		title.fromOneLine(sldFile.getName());
+
+		desc = new Translation();
+		desc.fromOneLine(sldFile.getAbsolutePath());
+	}
+
+	public void dispose() {
+	}
+
+	/**
+	 * Returnes human readable {@link String} of the CRS natively used by this
+	 * {@link DpLayer}
+	 * 
+	 * If crs == null, it will call {@link #getGeoObject()}
+	 * 
+	 */
+	public String getCRSString() {
+		if (getCrs() == null)
+			return "CRS?";
+
+		return getCrs().getName().getCode();
+	}
+
+	public CoordinateReferenceSystem getCrs() {
+		return fs.getSchema().getDefaultGeometry().getCoordinateSystem();
+	}
+
+	public Translation getDesc() {
+		return desc;
+	}
+
+	public Envelope getEnvelope() {
+		try {
+			return fs.getBounds();
+		} catch (IOException e) {
+			e.printStackTrace();
+			return null;
+		}
+	}
+
+	public FeatureSource getGeoObject() {
+		return fs;
+	}
+
+	public String getId() {
+		return id;
+	}
+
+	public ImageIcon getImageIcon() {
+		return null;
+	}
+
+	public URL getInfoURL() {
+		return null;
+	}
+
+	public Translation getKeywords() {
+		return null;
+	}
+
+	public Style getStyle() {
+		return style;
+	}
+
+	public Translation getTitle() {
+		return title;
+	}
+
+	public boolean isDisposed() {
+		return false;
+	}
+
+	/**
+	 * If true, this layer will not be shown in the legend. Default = false
+	 */
+	/**
+	 * 
+	 * Killed by SK: 6. April 09: Ein Layer soll nicht generell auf
+	 * verstecken/nicht verstecken gestellt werden können. Das sind
+	 * Eigenschaften der Karte/MapContext, ebenso wie die Reihenfolge der Layer.
+	 * Im Atlas verwaltet deshalb nun die Klasse skrueger.atlas.Map welche Layer
+	 * nicht in der Legende auftauchen sollen. Meines Wissens hat keiner bisher
+	 * die Funktion genutzt.
+	 * 
+	 * // public boolean isHideInLegend() { // return false; // }
+	 */
+
+	public void setDesc(Translation dec) {
+		this.desc = dec;
+	}
+
+	public void setImageIcon(ImageIcon icon) {
+	}
+
+	public void setKeywords(Translation keywords) {
+	}
+
+	public void setStyle(Style style) {
+		this.style = style;
+
+	}
+
+	public void setTitle(Translation title) {
+		this.title = title;
+
+	}
+
+	public void uncache() {
+	}
+
+	/**
+	 * 
+	 */
+	public Map<Integer, AttributeMetaData> getAttributeMetaDataMap() {
+		if (map == null) {
+
+			map = new HashMap<Integer, AttributeMetaData>();
+
+			// Leaving out the first one, it will be the_geom
+			for (int i = 1; i < fs.getSchema().getAttributeCount(); i++) {
+				AttributeType att = fs.getSchema().getAttributeType(i);
+
+				AttributeMetaData attMetaData = new AttributeMetaData(i, att
+						.getLocalName());
+				map.put(i, attMetaData);
+			}
+		}
+		return map;
+	}
+
+	/**
+	 * @return The {@link File} where the SLD was loaded from or
+	 *         <code>null</code> if there didn't exist a {@link File}. 
+	 * 
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+	 *         Kr&uuml;ger</a>
+	 */
+	public File getSldFile() {
+		return sldFile;
+	}
+
+	public void setSldFile(File sldFile) {
+		this.sldFile = sldFile;
+	}
+
+	/**
+	 * Returns the features of the {@link FeatureSource}.
+	 * 
+	 * @see {@link StyledFeaturesInterface}
+	 */
+	@Override
+	public FeatureCollection getFeatureCollection() {
+		FeatureCollection features;
+		try {
+			features = getGeoObject().getFeatures();
+		} catch (IOException e) {
+			throw new RuntimeException(
+					"Error getting the features of the  FeatureSource");
+		}
+		return features;
+	}
+
+	/**
+	 * Same as {@link #getGeoObject()} method, but complies to the
+	 * {@link StyledFeaturesInterface}
+	 * 
+	 * @see {@link StyledFeaturesInterface}
+	 */
+	@Override
+	public FeatureSource getFeatureSource() {
+		return getGeoObject();
+	}
+
+}

Modified: trunk/src/skrueger/geotools/StyledFeatureCollection.java
===================================================================
--- trunk/src/skrueger/geotools/StyledFeatureCollection.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/StyledFeatureCollection.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,360 +1,389 @@
-package skrueger.geotools;
-
-import java.io.IOException;
-import java.net.URL;
-import java.util.HashMap;
-import java.util.Map;
-
-import javax.swing.ImageIcon;
-
-import org.geotools.data.FeatureSource;
-import org.geotools.data.collection.CollectionDataStore;
-import org.geotools.feature.AttributeType;
-import org.geotools.feature.FeatureCollection;
-import org.geotools.feature.FeatureType;
-import org.geotools.styling.Style;
-
-import schmitzm.geotools.feature.FeatureUtil;
-import skrueger.AttributeMetaData;
-import skrueger.i8n.Translation;
-
-/**
- * This class provides a simple implementation of {@link StyledLayerInterface} for
- * {@link FeatureCollection}. The uncache functionality is not supported,
- * because this class bases on an existing {@link FeatureCollection} object in
- * memory.
- * 
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- *         (University of Bonn/Germany)
- * @version 1.0
- */
-public class StyledFeatureCollection extends
-		AbstractStyledLayer<FeatureCollection> implements
-		StyledFeatureCollectionInterface {
-
-	/** Holds the meta data for displaying a legend. */
-	protected Map<Integer, AttributeMetaData> attrMetaData = null;
-
-	/**
-	 * We be filled with a "virtual" {@link FeatureSource} on demand.
-	 */
-	private FeatureSource featureSource = null;
-
-	/**
-	 * Creates a styled {@link FeatureCollection} with language-specific
-	 * informations.
-	 * 
-	 * @param fc
-	 *            the {@link FeatureCollection}
-	 * @param id
-	 *            a unique ID for the object
-	 * @param title
-	 *            a (language-specific) short description
-	 * @param desc
-	 *            a (language-specific) long description
-	 * @param keywords
-	 *            (language-specific) keywords for the geo objects
-	 * @param style
-	 *            a display style (if {@code null}, a default style is created)
-	 * @param attrMetaData
-	 *            meta data for displaying a legend
-	 * @param icon
-	 *            an icon for the object (can be {@code null})
-	 * @exception IllegalArgumentException
-	 *                if {@code null} is given as ID or geo object
-	 */
-	public StyledFeatureCollection(FeatureCollection fc, String id,
-			Translation title, Translation desc, Translation keywords,
-			Style style, Map<Integer, AttributeMetaData> attrMetaData,
-			ImageIcon icon) {
-		super(fc, fc.getBounds(), fc.getSchema().getDefaultGeometry()
-				.getCoordinateSystem(), id, title, desc, keywords, style, icon);
-		setAttributeMetaData(attrMetaData);
-	}
-
-	/**
-	 * Creates a styled {@link FeatureCollection} with language-specific
-	 * informations.
-	 * 
-	 * @param fc
-	 *            the {@link FeatureCollection}
-	 * @param id
-	 *            a unique ID for the object
-	 * @param title
-	 *            a (language-specific) short description
-	 * @param desc
-	 *            a (language-specific) long description
-	 * @param keywords
-	 *            (language-specific) keywords for the geo objects
-	 * @param style
-	 *            a display style with attribute meta data information
-	 * @param icon
-	 *            an icon for the object (can be {@code null})
-	 * @exception IllegalArgumentException
-	 *                if {@code null} is given as ID or geo object
-	 */
-	public StyledFeatureCollection(FeatureCollection fc, String id,
-			Translation title, Translation desc, Translation keywords,
-			StyledLayerStyle<Map<Integer, AttributeMetaData>> style,
-			ImageIcon icon) {
-		super(fc, fc.getBounds(), fc.getSchema().getDefaultGeometry()
-				.getCoordinateSystem(), id, title, desc, keywords,
-				style != null ? style.getGeoObjectStyle() : null, icon);
-		setAttributeMetaData(style != null ? style.getMetaData() : null);
-	}
-
-	/**
-	 * Creates a styled {@link FeatureCollection} with a language-specific
-	 * title, no long description, no keywords, default attribute meta data and
-	 * no icon.
-	 * 
-	 * @param fc
-	 *            the {@link FeatureCollection}
-	 * @param id
-	 *            a unique ID for the object
-	 * @param title
-	 *            a short description
-	 * @param style
-	 *            a display style (if {@code null}, a default style is created)
-	 * @exception IllegalArgumentException
-	 *                if {@code null} is given as ID or geo object
-	 * @see #createDefaultAttributeMetaDataMap(FeatureCollection)
-	 */
-	public StyledFeatureCollection(FeatureCollection fc, String id,
-			Translation title, Style style) {
-		this(fc, id, title, null, null, style, null, null);
-	}
-
-	/**
-	 * Creates a styled {@link FeatureCollection} with non-translated
-	 * informations.
-	 * 
-	 * @param fc
-	 *            the {@link FeatureCollection}
-	 * @param id
-	 *            a unique ID for the object
-	 * @param title
-	 *            a short description
-	 * @param desc
-	 *            a long description
-	 * @param keywords
-	 *            keywords for the geo objects
-	 * @param style
-	 *            a display style (if {@code null}, a default style is created)
-	 * @param attrMetaData
-	 *            meta data for displaying a legend
-	 * @param icon
-	 *            an icon for the object (can be {@code null})
-	 * @exception IllegalArgumentException
-	 *                if {@code null} is given as ID or geo object
-	 */
-	public StyledFeatureCollection(FeatureCollection fc, String id,
-			String title, String desc, String keywords, Style style,
-			Map<Integer, AttributeMetaData> attrMetaData, ImageIcon icon) {
-		this(fc, id, (Translation) null, null, null, style, attrMetaData, icon);
-		setTitle(title);
-		setDesc(desc);
-		setKeywords(keywords);
-	}
-
-	/**
-	 * Creates a styled {@link FeatureCollection} with non-translated
-	 * informations.
-	 * 
-	 * @param fc
-	 *            the {@link FeatureCollection}
-	 * @param id
-	 *            a unique ID for the object
-	 * @param title
-	 *            a short description
-	 * @param desc
-	 *            a long description
-	 * @param keywords
-	 *            keywords for the geo objects
-	 * @param style
-	 *            a display style with attribute meta data information
-	 * @param icon
-	 *            an icon for the object (can be {@code null})
-	 * @exception IllegalArgumentException
-	 *                if {@code null} is given as ID or geo object
-	 */
-	public StyledFeatureCollection(FeatureCollection fc, String id,
-			String title, String desc, String keywords,
-			StyledLayerStyle<Map<Integer, AttributeMetaData>> style,
-			ImageIcon icon) {
-		this(fc, id, title, desc, keywords, style != null ? style
-				.getGeoObjectStyle() : null, style != null ? style
-				.getMetaData() : null, icon);
-	}
-
-	/**
-	 * Creates a styled {@link FeatureCollection} with a non-translated title,
-	 * no long description, no keywords, default attribute meta data and no
-	 * icon.
-	 * 
-	 * @param fc
-	 *            the {@link FeatureCollection}
-	 * @param id
-	 *            a unique ID for the object
-	 * @param title
-	 *            a short description
-	 * @param style
-	 *            a display style (if {@code null}, a default style is created)
-	 * @exception IllegalArgumentException
-	 *                if {@code null} is given as ID or geo object
-	 * @see #createDefaultAttributeMetaDataMap(FeatureCollection)
-	 */
-	public StyledFeatureCollection(FeatureCollection fc, String id,
-			String title, Style style) {
-		this(fc, id, title, null, null, style, null, null);
-	}
-
-	/**
-	 * Creates a styled {@link FeatureCollection} with a non-translated title,
-	 * no long description, no keywords, default attribute meta data and no
-	 * icon.
-	 * 
-	 * @param fc
-	 *            the {@link FeatureCollection}
-	 * @param id
-	 *            a unique ID for the object
-	 * @param title
-	 *            a short description
-	 * @param style
-	 *            a display style (if {@code null}, a default style is created)
-	 * @exception IllegalArgumentException
-	 *                if {@code null} is given as ID or geo object
-	 * @see #createDefaultAttributeMetaDataMap(FeatureCollection)
-	 */
-	public StyledFeatureCollection(FeatureCollection fc, String id,
-			String title, StyledLayerStyle<Map<Integer, AttributeMetaData>> style) {
-		this(fc, id, title, null, null, style != null ? style
-				.getGeoObjectStyle() : null, style != null ? style
-				.getMetaData() : null, null);
-	}
-
-	/**
-	 * Creates a default style for the {@link FeatureCollection}.
-	 * 
-	 * @see FeatureUtil#createDefaultStyle(FeatureCollection)
-	 */
-	protected Style createDefaultStyle() {
-		return FeatureUtil.createDefaultStyle(geoObject);
-	}
-
-	/**
-	 * Returns the meta data needed for displaying a legend.
-	 */
-	public Map<Integer, AttributeMetaData> getAttributeMetaDataMap() {
-		return attrMetaData;
-	}
-
-	/**
-	 * Sets the meta data needed for displaying a legend. If {@code legendData}
-	 * is {@code null} an empty map is set, so
-	 * {@link #getAttributeMetaDataMap()} never returns {@code null}.
-	 * 
-	 * @param attrMetaData
-	 *            map of attribute meta data
-	 */
-	public void setAttributeMetaData(
-			Map<Integer, AttributeMetaData> attrMetaData) {
-		this.attrMetaData = (attrMetaData != null) ? attrMetaData
-				: createDefaultAttributeMetaDataMap(geoObject);
-	}
-
-	/**
-	 * Creates non-translated default meta data for a {@link FeatureCollection}
-	 * with all attributes visible and no unit set.
-	 * 
-	 * @param fc
-	 *            a {@link FeatureCollection}
-	 */
-	public static Map<Integer, AttributeMetaData> createDefaultAttributeMetaDataMap(
-			FeatureCollection fc) {
-		HashMap<Integer, AttributeMetaData> metaDataMap = new HashMap<Integer, AttributeMetaData>();
-		FeatureType ftype = fc.getSchema();
-		for (int i = 0; i < ftype.getAttributeCount(); i++) {
-			AttributeType aType = ftype.getAttributeType(i);
-			if (aType != ftype.getDefaultGeometry())
-				metaDataMap.put(i, new AttributeMetaData(i, // Column no.
-						true, // visible
-						new Translation(aType.getName()), // Column name
-						new Translation(), // description
-						"" // Unit
-				));
-		}
-		return metaDataMap;
-	}
-
-	/**
-	 * Simply sets the {@link #geoObject}, {@link #crs}, {@link #envelope} and
-	 * {@link #attrMetaData} to {@code null}.
-	 */
-	public void dispose() {
-		this.geoObject = null;
-		this.envelope = null;
-		this.crs = null;
-		this.attrMetaData = null;
-	}
-
-	/**
-	 * Tests whether the geo object is disposed.
-	 */
-	public boolean isDisposed() {
-		return geoObject == null;
-	}
-
-	/**
-	 * Does nothing, because the {@link AbstractStyledLayer} bases on existing
-	 * objects (in memory) which can not be uncached and reloaded.
-	 */
-	public void uncache() {
-
-		/** It will be recreated on the next getFetureSource() **/
-		featureSource = null;
-
-		LOGGER
-				.warn("Uncache onyl uncached any virtual FeatureSource. Object remains in memory.");
-	}
-
-	/*
-	 * (non-Javadoc)
-	 * 
-	 * @see skrueger.geotools.StyledLayerInterface#getInfoURL()
-	 */
-	public URL getInfoURL() {
-		return null;
-	}
-
-	/**
-	 * Same as {@link #getGeoObject()} method, but complies to the {@link StyledFeaturesInterface} 
-	 * @see {@link StyledFeaturesInterface}
-	 */
-	@Override
-	public FeatureCollection getFeatureCollection() {
-		return getGeoObject();
-	}
-
-	/**
-	 * Returns a virtual {@link FeatureSource} to access the
-	 * {@link FeatureCollection}. Once created, it will be reused until
-	 * {@link #uncache()} is called.<br/>
-	 * @see {@link StyledFeaturesInterface}
-	 */
-	@Override
-	public FeatureSource getFeatureSource() {
-		if (featureSource == null) {
-			CollectionDataStore store = new CollectionDataStore(getGeoObject());
-			try {
-				featureSource = store.getFeatureSource(store.getTypeNames()[0]);
-			} catch (IOException e) {
-				throw new RuntimeException(
-						"Could not create a FeatureSource from the CollectionDataStore:",
-						e);
-			}
-		}
-		return featureSource;
-	}
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package skrueger.geotools;
+
+import java.io.IOException;
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.swing.ImageIcon;
+
+import org.geotools.data.FeatureSource;
+import org.geotools.data.collection.CollectionDataStore;
+import org.geotools.feature.AttributeType;
+import org.geotools.feature.FeatureCollection;
+import org.geotools.feature.FeatureType;
+import org.geotools.styling.Style;
+
+import schmitzm.geotools.feature.FeatureUtil;
+import skrueger.AttributeMetaData;
+import skrueger.i8n.Translation;
+
+/**
+ * This class provides a simple implementation of {@link StyledLayerInterface} for
+ * {@link FeatureCollection}. The uncache functionality is not supported,
+ * because this class bases on an existing {@link FeatureCollection} object in
+ * memory.
+ * 
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *         (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class StyledFeatureCollection extends
+		AbstractStyledLayer<FeatureCollection> implements
+		StyledFeatureCollectionInterface {
+
+	/** Holds the meta data for displaying a legend. */
+	protected Map<Integer, AttributeMetaData> attrMetaData = null;
+
+	/**
+	 * We be filled with a "virtual" {@link FeatureSource} on demand.
+	 */
+	private FeatureSource featureSource = null;
+
+	/**
+	 * Creates a styled {@link FeatureCollection} with language-specific
+	 * informations.
+	 * 
+	 * @param fc
+	 *            the {@link FeatureCollection}
+	 * @param id
+	 *            a unique ID for the object
+	 * @param title
+	 *            a (language-specific) short description
+	 * @param desc
+	 *            a (language-specific) long description
+	 * @param keywords
+	 *            (language-specific) keywords for the geo objects
+	 * @param style
+	 *            a display style (if {@code null}, a default style is created)
+	 * @param attrMetaData
+	 *            meta data for displaying a legend
+	 * @param icon
+	 *            an icon for the object (can be {@code null})
+	 * @exception IllegalArgumentException
+	 *                if {@code null} is given as ID or geo object
+	 */
+	public StyledFeatureCollection(FeatureCollection fc, String id,
+			Translation title, Translation desc, Translation keywords,
+			Style style, Map<Integer, AttributeMetaData> attrMetaData,
+			ImageIcon icon) {
+		super(fc, fc.getBounds(), fc.getSchema().getDefaultGeometry()
+				.getCoordinateSystem(), id, title, desc, keywords, style, icon);
+		setAttributeMetaData(attrMetaData);
+	}
+
+	/**
+	 * Creates a styled {@link FeatureCollection} with language-specific
+	 * informations.
+	 * 
+	 * @param fc
+	 *            the {@link FeatureCollection}
+	 * @param id
+	 *            a unique ID for the object
+	 * @param title
+	 *            a (language-specific) short description
+	 * @param desc
+	 *            a (language-specific) long description
+	 * @param keywords
+	 *            (language-specific) keywords for the geo objects
+	 * @param style
+	 *            a display style with attribute meta data information
+	 * @param icon
+	 *            an icon for the object (can be {@code null})
+	 * @exception IllegalArgumentException
+	 *                if {@code null} is given as ID or geo object
+	 */
+	public StyledFeatureCollection(FeatureCollection fc, String id,
+			Translation title, Translation desc, Translation keywords,
+			StyledLayerStyle<Map<Integer, AttributeMetaData>> style,
+			ImageIcon icon) {
+		super(fc, fc.getBounds(), fc.getSchema().getDefaultGeometry()
+				.getCoordinateSystem(), id, title, desc, keywords,
+				style != null ? style.getGeoObjectStyle() : null, icon);
+		setAttributeMetaData(style != null ? style.getMetaData() : null);
+	}
+
+	/**
+	 * Creates a styled {@link FeatureCollection} with a language-specific
+	 * title, no long description, no keywords, default attribute meta data and
+	 * no icon.
+	 * 
+	 * @param fc
+	 *            the {@link FeatureCollection}
+	 * @param id
+	 *            a unique ID for the object
+	 * @param title
+	 *            a short description
+	 * @param style
+	 *            a display style (if {@code null}, a default style is created)
+	 * @exception IllegalArgumentException
+	 *                if {@code null} is given as ID or geo object
+	 * @see #createDefaultAttributeMetaDataMap(FeatureCollection)
+	 */
+	public StyledFeatureCollection(FeatureCollection fc, String id,
+			Translation title, Style style) {
+		this(fc, id, title, null, null, style, null, null);
+	}
+
+	/**
+	 * Creates a styled {@link FeatureCollection} with non-translated
+	 * informations.
+	 * 
+	 * @param fc
+	 *            the {@link FeatureCollection}
+	 * @param id
+	 *            a unique ID for the object
+	 * @param title
+	 *            a short description
+	 * @param desc
+	 *            a long description
+	 * @param keywords
+	 *            keywords for the geo objects
+	 * @param style
+	 *            a display style (if {@code null}, a default style is created)
+	 * @param attrMetaData
+	 *            meta data for displaying a legend
+	 * @param icon
+	 *            an icon for the object (can be {@code null})
+	 * @exception IllegalArgumentException
+	 *                if {@code null} is given as ID or geo object
+	 */
+	public StyledFeatureCollection(FeatureCollection fc, String id,
+			String title, String desc, String keywords, Style style,
+			Map<Integer, AttributeMetaData> attrMetaData, ImageIcon icon) {
+		this(fc, id, (Translation) null, null, null, style, attrMetaData, icon);
+		setTitle(title);
+		setDesc(desc);
+		setKeywords(keywords);
+	}
+
+	/**
+	 * Creates a styled {@link FeatureCollection} with non-translated
+	 * informations.
+	 * 
+	 * @param fc
+	 *            the {@link FeatureCollection}
+	 * @param id
+	 *            a unique ID for the object
+	 * @param title
+	 *            a short description
+	 * @param desc
+	 *            a long description
+	 * @param keywords
+	 *            keywords for the geo objects
+	 * @param style
+	 *            a display style with attribute meta data information
+	 * @param icon
+	 *            an icon for the object (can be {@code null})
+	 * @exception IllegalArgumentException
+	 *                if {@code null} is given as ID or geo object
+	 */
+	public StyledFeatureCollection(FeatureCollection fc, String id,
+			String title, String desc, String keywords,
+			StyledLayerStyle<Map<Integer, AttributeMetaData>> style,
+			ImageIcon icon) {
+		this(fc, id, title, desc, keywords, style != null ? style
+				.getGeoObjectStyle() : null, style != null ? style
+				.getMetaData() : null, icon);
+	}
+
+	/**
+	 * Creates a styled {@link FeatureCollection} with a non-translated title,
+	 * no long description, no keywords, default attribute meta data and no
+	 * icon.
+	 * 
+	 * @param fc
+	 *            the {@link FeatureCollection}
+	 * @param id
+	 *            a unique ID for the object
+	 * @param title
+	 *            a short description
+	 * @param style
+	 *            a display style (if {@code null}, a default style is created)
+	 * @exception IllegalArgumentException
+	 *                if {@code null} is given as ID or geo object
+	 * @see #createDefaultAttributeMetaDataMap(FeatureCollection)
+	 */
+	public StyledFeatureCollection(FeatureCollection fc, String id,
+			String title, Style style) {
+		this(fc, id, title, null, null, style, null, null);
+	}
+
+	/**
+	 * Creates a styled {@link FeatureCollection} with a non-translated title,
+	 * no long description, no keywords, default attribute meta data and no
+	 * icon.
+	 * 
+	 * @param fc
+	 *            the {@link FeatureCollection}
+	 * @param id
+	 *            a unique ID for the object
+	 * @param title
+	 *            a short description
+	 * @param style
+	 *            a display style (if {@code null}, a default style is created)
+	 * @exception IllegalArgumentException
+	 *                if {@code null} is given as ID or geo object
+	 * @see #createDefaultAttributeMetaDataMap(FeatureCollection)
+	 */
+	public StyledFeatureCollection(FeatureCollection fc, String id,
+			String title, StyledLayerStyle<Map<Integer, AttributeMetaData>> style) {
+		this(fc, id, title, null, null, style != null ? style
+				.getGeoObjectStyle() : null, style != null ? style
+				.getMetaData() : null, null);
+	}
+
+	/**
+	 * Creates a default style for the {@link FeatureCollection}.
+	 * 
+	 * @see FeatureUtil#createDefaultStyle(FeatureCollection)
+	 */
+	protected Style createDefaultStyle() {
+		return FeatureUtil.createDefaultStyle(geoObject);
+	}
+
+	/**
+	 * Returns the meta data needed for displaying a legend.
+	 */
+	public Map<Integer, AttributeMetaData> getAttributeMetaDataMap() {
+		return attrMetaData;
+	}
+
+	/**
+	 * Sets the meta data needed for displaying a legend. If {@code legendData}
+	 * is {@code null} an empty map is set, so
+	 * {@link #getAttributeMetaDataMap()} never returns {@code null}.
+	 * 
+	 * @param attrMetaData
+	 *            map of attribute meta data
+	 */
+	public void setAttributeMetaData(
+			Map<Integer, AttributeMetaData> attrMetaData) {
+		this.attrMetaData = (attrMetaData != null) ? attrMetaData
+				: createDefaultAttributeMetaDataMap(geoObject);
+	}
+
+	/**
+	 * Creates non-translated default meta data for a {@link FeatureCollection}
+	 * with all attributes visible and no unit set.
+	 * 
+	 * @param fc
+	 *            a {@link FeatureCollection}
+	 */
+	public static Map<Integer, AttributeMetaData> createDefaultAttributeMetaDataMap(
+			FeatureCollection fc) {
+		HashMap<Integer, AttributeMetaData> metaDataMap = new HashMap<Integer, AttributeMetaData>();
+		FeatureType ftype = fc.getSchema();
+		for (int i = 0; i < ftype.getAttributeCount(); i++) {
+			AttributeType aType = ftype.getAttributeType(i);
+			if (aType != ftype.getDefaultGeometry())
+				metaDataMap.put(i, new AttributeMetaData(i, // Column no.
+						true, // visible
+						new Translation(aType.getName()), // Column name
+						new Translation(), // description
+						"" // Unit
+				));
+		}
+		return metaDataMap;
+	}
+
+	/**
+	 * Simply sets the {@link #geoObject}, {@link #crs}, {@link #envelope} and
+	 * {@link #attrMetaData} to {@code null}.
+	 */
+	public void dispose() {
+		this.geoObject = null;
+		this.envelope = null;
+		this.crs = null;
+		this.attrMetaData = null;
+	}
+
+	/**
+	 * Tests whether the geo object is disposed.
+	 */
+	public boolean isDisposed() {
+		return geoObject == null;
+	}
+
+	/**
+	 * Does nothing, because the {@link AbstractStyledLayer} bases on existing
+	 * objects (in memory) which can not be uncached and reloaded.
+	 */
+	public void uncache() {
+
+		/** It will be recreated on the next getFetureSource() **/
+		featureSource = null;
+
+		LOGGER
+				.warn("Uncache onyl uncached any virtual FeatureSource. Object remains in memory.");
+	}
+
+	/*
+	 * (non-Javadoc)
+	 * 
+	 * @see skrueger.geotools.StyledLayerInterface#getInfoURL()
+	 */
+	public URL getInfoURL() {
+		return null;
+	}
+
+	/**
+	 * Same as {@link #getGeoObject()} method, but complies to the {@link StyledFeaturesInterface} 
+	 * @see {@link StyledFeaturesInterface}
+	 */
+	@Override
+	public FeatureCollection getFeatureCollection() {
+		return getGeoObject();
+	}
+
+	/**
+	 * Returns a virtual {@link FeatureSource} to access the
+	 * {@link FeatureCollection}. Once created, it will be reused until
+	 * {@link #uncache()} is called.<br/>
+	 * @see {@link StyledFeaturesInterface}
+	 */
+	@Override
+	public FeatureSource getFeatureSource() {
+		if (featureSource == null) {
+			CollectionDataStore store = new CollectionDataStore(getGeoObject());
+			try {
+				featureSource = store.getFeatureSource(store.getTypeNames()[0]);
+			} catch (IOException e) {
+				throw new RuntimeException(
+						"Could not create a FeatureSource from the CollectionDataStore:",
+						e);
+			}
+		}
+		return featureSource;
+	}
+
+}

Modified: trunk/src/skrueger/geotools/StyledFeatureCollectionInterface.java
===================================================================
--- trunk/src/skrueger/geotools/StyledFeatureCollectionInterface.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/StyledFeatureCollectionInterface.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,14 +1,43 @@
-package skrueger.geotools;
-
-import java.util.Map;
-
-import org.geotools.feature.FeatureCollection;
-
-import skrueger.AttributeMetaData;
-
-/**
- * {@link StyledLayerInterface} which contains a {@link FeatureCollection} as geo object.<br>
- */
-public interface StyledFeatureCollectionInterface extends StyledFeaturesInterface<FeatureCollection> {
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package skrueger.geotools;
+
+import java.util.Map;
+
+import org.geotools.feature.FeatureCollection;
+
+import skrueger.AttributeMetaData;
+
+/**
+ * {@link StyledLayerInterface} which contains a {@link FeatureCollection} as geo object.<br>
+ */
+public interface StyledFeatureCollectionInterface extends StyledFeaturesInterface<FeatureCollection> {
+
+}

Modified: trunk/src/skrueger/geotools/StyledFeatureCollectionTableModel.java
===================================================================
--- trunk/src/skrueger/geotools/StyledFeatureCollectionTableModel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/StyledFeatureCollectionTableModel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,301 +1,320 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-package skrueger.geotools;
-
-import java.util.Iterator;
-import java.util.Map;
-import java.util.Vector;
-
-import org.apache.log4j.Logger;
-import org.geotools.data.DefaultQuery;
-import org.geotools.data.FeatureSource;
-import org.geotools.data.Query;
-import org.geotools.data.memory.MemoryDataStore;
-import org.geotools.feature.AttributeType;
-import org.geotools.feature.FeatureCollection;
-import org.opengis.filter.Filter;
-
-import schmitzm.geotools.gui.FeatureCollectionTableModel;
-import skrueger.AttributeMetaData;
-import skrueger.i8n.I8NUtil;
-import skrueger.i8n.Translation;
-
-import com.vividsolutions.jts.geom.Envelope;
-
-/**
- * This class extends the the {@link FeatureCollectionTableModel} with the
- * functionalities of the {@link AttributeMetaData} of
- * {@linkplain StyledLayerInterface styled objects}.
- * <ul>
- * <li>column names are translated according to
- * {@link AttributeMetaData#getTitle()}</li>
- * <li>columns are hidden according to {@link AttributeMetaData#isVisible()()}</li>
- * </ul>
- * 
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- *         (University of Bonn/Germany)
- */
-public class StyledFeatureCollectionTableModel extends
-		FeatureCollectionTableModel {
-	final static private Logger LOGGER = Logger
-			.getLogger(StyledFeatureCollectionTableModel.class);
-	/** Holds the data source as styled layer. */
-	protected StyledLayerInterface<?> layer = null;
-	/** Contains only the visible elements of the {@link AttributeMetaData}-Map */
-	protected Map<Integer, AttributeMetaData> visibleAMD = null;
-	/** Holds the data source for the table as {@code FeatureSource}. */
-	protected FeatureSource featureSource = null;
-	/** Contains the complete {@link AttributeMetaData}-Map of the styled layer. */
-	protected Map<Integer, AttributeMetaData> origAMD = null;
-	/** Holds the current filter on the table */
-	protected Filter filter = null;
-	/** Holds the Bounds for all features. Only set once during the constructor **/
-	protected Envelope bounds;
-
-	
-
-	/**
-	 * Creates a new table model for a styled layer.
-	 * 
-	 * @param layer
-	 *            the styled layer
-	 */
-	public StyledFeatureCollectionTableModel(
-			StyledFeatureCollectionInterface layer) {
-		this(layer, Filter.INCLUDE);
-	}
-
-	/**
-	 * Creates a new table model for a styled layer.
-	 * 
-	 * @param layer
-	 *            the styled layer
-	 * @param filter
-	 *            filter applied to the table
-	 */
-	public StyledFeatureCollectionTableModel(
-			StyledFeatureCollectionInterface layer, Filter filter) {
-		super();
-		setFeatureCollection(layer, filter);
-	}
-
-
-	/**
-	 * Creates a new table model for a styled layer.
-	 * 
-	 * @param layer
-	 *            the styled layer
-	 */
-	public StyledFeatureCollectionTableModel(StyledFeaturesInterface layer) {
-		this(layer, Filter.INCLUDE);
-	}
-
-	/**
-	 * Creates a new table model for a styled layer.
-	 * 
-	 * @param layer
-	 *            the styled layer
-	 * @param filter
-	 *            filter applied to the table
-	 */
-	public StyledFeatureCollectionTableModel(StyledFeaturesInterface layer,
-			Filter filter) {
-		super();
-		setFeatureCollection(layer, filter);
-	}
-
-	/**
-	 * Sets a new data source for the table.
-	 * 
-	 * @param fs
-	 *            the feature source
-	 * @param amd
-	 *            {@link AttributeMetaData}-Map to define the visible attributes
-	 *            and translation
-	 */
-	protected void setFeatureSource(FeatureSource fs,
-			Map<Integer, AttributeMetaData> amd, Filter filter)
-			throws Exception {
-		if (filter == null)
-			filter = Filter.INCLUDE;
-
-		this.featureSource = fs;
-		this.filter = filter;
-		this.origAMD = amd;
-		this.visibleAMD = null;
-
-		FeatureCollection fc = null;
-		if (fs != null) {
-
-			bounds = fs.getBounds();
-
-			Query query = new DefaultQuery(fs.getSchema().getTypeName(), filter);
-			if (amd != null) {
-				// determine the names of the visible Attributes
-				this.visibleAMD = StyledLayerUtil.getVisibleAttributeMetaData(
-						amd, true);
-				Vector<String> visibleAttrNames = new Vector<String>();
-				// Add the column with the geometry (usually "the_geom")
-				visibleAttrNames.add(fs.getSchema().getDefaultGeometry()
-						.getLocalName());
-				for (int attrIdx : visibleAMD.keySet()) {
-
-					/**
-					 * If the user removed columns from the schema of the DBF
-					 * file, there might exist AttributeMetaData for columns
-					 * that don't exists. We check here to avoid an
-					 * ArrayOutOfIndex.
-					 */
-					if (attrIdx < fs.getSchema().getAttributeCount()) {
-						final AttributeType attributeTypeAtIdx = fs.getSchema()
-								.getAttributeType(attrIdx);
-						visibleAttrNames.add(attributeTypeAtIdx.getLocalName());
-					} else {
-						LOGGER.warn("AttributeMetaData has been found for columnIdx="+attrIdx+", but fs.getSchema().getAttributeCount() = "+fs.getSchema().getAttributeCount()+". Ignored.");
-					}
-				}
-
-				// create a query for the visible attributes
-				String[] properties = visibleAttrNames.toArray(new String[0]);
-
-				LOGGER.debug("Query contains the following attributes: "
-						+ visibleAttrNames);
-
-				query = new DefaultQuery(fs.getSchema().getTypeName(), filter,
-						properties);
-			}
-			fc = fs.getFeatures(query);
-
-			// FAILS:!!!, even with query = new
-			// DefaultQuery(fs.getSchema().getTypeName(), filter);
-			// java.lang.UnsupportedOperationException: Unknown feature
-			// attribute: PQM_MOD
-			// at
-			// schmitzm.geotools.feature.FeatureOperationTree.evaluate(FeatureOperationTree.java:93)
-			// bounds = fc.getBounds();
-			// SK, 17.4.2009
-			//      
-			// System.out.println("Filter = "+filter);
-			// System.out.println("Size of FC = "+fc.size());
-			// System.out.println("anz att= "+fc.getNumberOfAttributes());
-		}
-		setFeatureCollection(fc);
-	}
-
-	/**
-	 * Converts the {@code StyledFeatureCollection} to a {@code FeatureSource}
-	 * and sets this as the new data source for the table.
-	 * 
-	 * @param fs
-	 *            the feature source
-	 * @param amd
-	 *            {@link AttributeMetaData}-Map to define the visible attributes
-	 *            and translation
-	 */
-	public void setFeatureCollection(StyledFeaturesInterface layer,
-			Filter filter) {
-		this.layer = layer;
-		try {
-			if (layer == null)
-				setFeatureSource(null, null, null);
-			else {
-				FeatureCollection fc = layer.getFeatureCollection();
-				String fcName = fc.getSchema().getTypeName();
-				FeatureSource fs = new MemoryDataStore(fc)
-						.getFeatureSource(fcName);
-				setFeatureSource(fs, layer.getAttributeMetaDataMap(), filter);
-			}
-		} catch (Exception err) {
-			throw new RuntimeException(err);
-		}
-	}
-
-	/**
-	 * Sets the {@code StyledFeatureCollection} as new data source for the
-	 * table.
-	 * 
-	 * @param fs
-	 *            the feature source
-	 * @param amd
-	 *            {@link AttributeMetaData}-Map to define the visible attributes
-	 *            and translation
-	 */
-	public void setFeatureCollection(StyledFeatureSourceInterface layer,
-			Filter filter) {
-		this.layer = layer;
-		try {
-			if (layer == null)
-				setFeatureSource(null, null, null);
-			else
-				setFeatureSource(layer.getGeoObject(), layer
-						.getAttributeMetaDataMap(), filter);
-		} catch (Exception err) {
-			throw new RuntimeException(err);
-		}
-	}
-
-	/**
-	 * Resets the filter for the table.
-	 * 
-	 * @param filter
-	 *            a filter
-	 */
-	public void setFilter(Filter filter) {
-		try {
-			setFeatureSource(this.featureSource, this.origAMD, filter);
-		} catch (Exception err) {
-			LOGGER.error("Setting the filter of the table model", err);
-			throw new RuntimeException(err);
-		}
-	}
-
-	/**
-	 * @return <code>Filter.INCLUDE</code> or the {@link Filter} applied to the
-	 *         Features
-	 */
-	public Filter getFilter() {
-		return this.filter;
-	}
-
-	/**
-	 * After calling {@code super.reorganize(.)} this method replaced the column
-	 * descriptions with the titles of the {@code AttributeMetaData}.
-	 * 
-	 * @param fireTableStructureChanged
-	 *            indicates whether a table event is initiated after reorganize
-	 */
-	@Override
-	protected void reorganize(boolean fireTableStructureChanged) {
-		super.reorganize(false);
-		// translate the column names
-		if (visibleAMD != null) {
-			Iterator<Integer> keys = visibleAMD.keySet().iterator();
-			for (int i = 0; i < colNames.length && keys.hasNext(); i++) {
-				Translation title = visibleAMD.get(keys.next()).getTitle();
-				if (!I8NUtil.isEmpty(title)) {
-					// System.out.println("set colname " + i + " to " +
-					// title.toString());
-					colNames[i] = title.toString();
-				}
-			}
-		}
-		if (fireTableStructureChanged)
-			fireTableStructureChanged();
-	}
-
-	/**
-	 * @return Cached bounds for the whole dataset (without applying the filter)
-	 *         or <code>null</code>
-	 */
-	public Envelope getBounds() {
-		return bounds;
-	}
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package skrueger.geotools;
+
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Vector;
+
+import org.apache.log4j.Logger;
+import org.geotools.data.DefaultQuery;
+import org.geotools.data.FeatureSource;
+import org.geotools.data.Query;
+import org.geotools.data.memory.MemoryDataStore;
+import org.geotools.feature.AttributeType;
+import org.geotools.feature.FeatureCollection;
+import org.opengis.filter.Filter;
+
+import schmitzm.geotools.gui.FeatureCollectionTableModel;
+import skrueger.AttributeMetaData;
+import skrueger.i8n.I8NUtil;
+import skrueger.i8n.Translation;
+
+import com.vividsolutions.jts.geom.Envelope;
+
+/**
+ * This class extends the the {@link FeatureCollectionTableModel} with the
+ * functionalities of the {@link AttributeMetaData} of
+ * {@linkplain StyledLayerInterface styled objects}.
+ * <ul>
+ * <li>column names are translated according to
+ * {@link AttributeMetaData#getTitle()}</li>
+ * <li>columns are hidden according to {@link AttributeMetaData#isVisible()()}</li>
+ * </ul>
+ * 
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ *         (University of Bonn/Germany)
+ */
+public class StyledFeatureCollectionTableModel extends
+		FeatureCollectionTableModel {
+	final static private Logger LOGGER = Logger
+			.getLogger(StyledFeatureCollectionTableModel.class);
+	/** Holds the data source as styled layer. */
+	protected StyledLayerInterface<?> layer = null;
+	/** Contains only the visible elements of the {@link AttributeMetaData}-Map */
+	protected Map<Integer, AttributeMetaData> visibleAMD = null;
+	/** Holds the data source for the table as {@code FeatureSource}. */
+	protected FeatureSource featureSource = null;
+	/** Contains the complete {@link AttributeMetaData}-Map of the styled layer. */
+	protected Map<Integer, AttributeMetaData> origAMD = null;
+	/** Holds the current filter on the table */
+	protected Filter filter = null;
+	/** Holds the Bounds for all features. Only set once during the constructor **/
+	protected Envelope bounds;
+
+	
+
+	/**
+	 * Creates a new table model for a styled layer.
+	 * 
+	 * @param layer
+	 *            the styled layer
+	 */
+	public StyledFeatureCollectionTableModel(
+			StyledFeatureCollectionInterface layer) {
+		this(layer, Filter.INCLUDE);
+	}
+
+	/**
+	 * Creates a new table model for a styled layer.
+	 * 
+	 * @param layer
+	 *            the styled layer
+	 * @param filter
+	 *            filter applied to the table
+	 */
+	public StyledFeatureCollectionTableModel(
+			StyledFeatureCollectionInterface layer, Filter filter) {
+		super();
+		setFeatureCollection(layer, filter);
+	}
+
+
+	/**
+	 * Creates a new table model for a styled layer.
+	 * 
+	 * @param layer
+	 *            the styled layer
+	 */
+	public StyledFeatureCollectionTableModel(StyledFeaturesInterface layer) {
+		this(layer, Filter.INCLUDE);
+	}
+
+	/**
+	 * Creates a new table model for a styled layer.
+	 * 
+	 * @param layer
+	 *            the styled layer
+	 * @param filter
+	 *            filter applied to the table
+	 */
+	public StyledFeatureCollectionTableModel(StyledFeaturesInterface layer,
+			Filter filter) {
+		super();
+		setFeatureCollection(layer, filter);
+	}
+
+	/**
+	 * Sets a new data source for the table.
+	 * 
+	 * @param fs
+	 *            the feature source
+	 * @param amd
+	 *            {@link AttributeMetaData}-Map to define the visible attributes
+	 *            and translation
+	 */
+	protected void setFeatureSource(FeatureSource fs,
+			Map<Integer, AttributeMetaData> amd, Filter filter)
+			throws Exception {
+		if (filter == null)
+			filter = Filter.INCLUDE;
+
+		this.featureSource = fs;
+		this.filter = filter;
+		this.origAMD = amd;
+		this.visibleAMD = null;
+
+		FeatureCollection fc = null;
+		if (fs != null) {
+
+			bounds = fs.getBounds();
+
+			Query query = new DefaultQuery(fs.getSchema().getTypeName(), filter);
+			if (amd != null) {
+				// determine the names of the visible Attributes
+				this.visibleAMD = StyledLayerUtil.getVisibleAttributeMetaData(
+						amd, true);
+				Vector<String> visibleAttrNames = new Vector<String>();
+				// Add the column with the geometry (usually "the_geom")
+				visibleAttrNames.add(fs.getSchema().getDefaultGeometry()
+						.getLocalName());
+				for (int attrIdx : visibleAMD.keySet()) {
+
+					/**
+					 * If the user removed columns from the schema of the DBF
+					 * file, there might exist AttributeMetaData for columns
+					 * that don't exists. We check here to avoid an
+					 * ArrayOutOfIndex.
+					 */
+					if (attrIdx < fs.getSchema().getAttributeCount()) {
+						final AttributeType attributeTypeAtIdx = fs.getSchema()
+								.getAttributeType(attrIdx);
+						visibleAttrNames.add(attributeTypeAtIdx.getLocalName());
+					} else {
+						LOGGER.warn("AttributeMetaData has been found for columnIdx="+attrIdx+", but fs.getSchema().getAttributeCount() = "+fs.getSchema().getAttributeCount()+". Ignored.");
+					}
+				}
+
+				// create a query for the visible attributes
+				String[] properties = visibleAttrNames.toArray(new String[0]);
+
+				LOGGER.debug("Query contains the following attributes: "
+						+ visibleAttrNames);
+
+				query = new DefaultQuery(fs.getSchema().getTypeName(), filter,
+						properties);
+			}
+			fc = fs.getFeatures(query);
+
+			// FAILS:!!!, even with query = new
+			// DefaultQuery(fs.getSchema().getTypeName(), filter);
+			// java.lang.UnsupportedOperationException: Unknown feature
+			// attribute: PQM_MOD
+			// at
+			// schmitzm.geotools.feature.FeatureOperationTree.evaluate(FeatureOperationTree.java:93)
+			// bounds = fc.getBounds();
+			// SK, 17.4.2009
+			//      
+			// System.out.println("Filter = "+filter);
+			// System.out.println("Size of FC = "+fc.size());
+			// System.out.println("anz att= "+fc.getNumberOfAttributes());
+		}
+		setFeatureCollection(fc);
+	}
+
+	/**
+	 * Converts the {@code StyledFeatureCollection} to a {@code FeatureSource}
+	 * and sets this as the new data source for the table.
+	 * 
+	 * @param fs
+	 *            the feature source
+	 * @param amd
+	 *            {@link AttributeMetaData}-Map to define the visible attributes
+	 *            and translation
+	 */
+	public void setFeatureCollection(StyledFeaturesInterface layer,
+			Filter filter) {
+		this.layer = layer;
+		try {
+			if (layer == null)
+				setFeatureSource(null, null, null);
+			else {
+				FeatureCollection fc = layer.getFeatureCollection();
+				String fcName = fc.getSchema().getTypeName();
+				FeatureSource fs = new MemoryDataStore(fc)
+						.getFeatureSource(fcName);
+				setFeatureSource(fs, layer.getAttributeMetaDataMap(), filter);
+			}
+		} catch (Exception err) {
+			throw new RuntimeException(err);
+		}
+	}
+
+	/**
+	 * Sets the {@code StyledFeatureCollection} as new data source for the
+	 * table.
+	 * 
+	 * @param fs
+	 *            the feature source
+	 * @param amd
+	 *            {@link AttributeMetaData}-Map to define the visible attributes
+	 *            and translation
+	 */
+	public void setFeatureCollection(StyledFeatureSourceInterface layer,
+			Filter filter) {
+		this.layer = layer;
+		try {
+			if (layer == null)
+				setFeatureSource(null, null, null);
+			else
+				setFeatureSource(layer.getGeoObject(), layer
+						.getAttributeMetaDataMap(), filter);
+		} catch (Exception err) {
+			throw new RuntimeException(err);
+		}
+	}
+
+	/**
+	 * Resets the filter for the table.
+	 * 
+	 * @param filter
+	 *            a filter
+	 */
+	public void setFilter(Filter filter) {
+		try {
+			setFeatureSource(this.featureSource, this.origAMD, filter);
+		} catch (Exception err) {
+			LOGGER.error("Setting the filter of the table model", err);
+			throw new RuntimeException(err);
+		}
+	}
+
+	/**
+	 * @return <code>Filter.INCLUDE</code> or the {@link Filter} applied to the
+	 *         Features
+	 */
+	public Filter getFilter() {
+		return this.filter;
+	}
+
+	/**
+	 * After calling {@code super.reorganize(.)} this method replaced the column
+	 * descriptions with the titles of the {@code AttributeMetaData}.
+	 * 
+	 * @param fireTableStructureChanged
+	 *            indicates whether a table event is initiated after reorganize
+	 */
+	@Override
+	protected void reorganize(boolean fireTableStructureChanged) {
+		super.reorganize(false);
+		// translate the column names
+		if (visibleAMD != null) {
+			Iterator<Integer> keys = visibleAMD.keySet().iterator();
+			for (int i = 0; i < colNames.length && keys.hasNext(); i++) {
+				Translation title = visibleAMD.get(keys.next()).getTitle();
+				if (!I8NUtil.isEmpty(title)) {
+					// System.out.println("set colname " + i + " to " +
+					// title.toString());
+					colNames[i] = title.toString();
+				}
+			}
+		}
+		if (fireTableStructureChanged)
+			fireTableStructureChanged();
+	}
+
+	/**
+	 * @return Cached bounds for the whole dataset (without applying the filter)
+	 *         or <code>null</code>
+	 */
+	public Envelope getBounds() {
+		return bounds;
+	}
+}

Modified: trunk/src/skrueger/geotools/StyledFeatureSourceInterface.java
===================================================================
--- trunk/src/skrueger/geotools/StyledFeatureSourceInterface.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/StyledFeatureSourceInterface.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,14 +1,43 @@
-package skrueger.geotools;
-
-import java.util.Map;
-
-import org.geotools.data.FeatureSource;
-
-import skrueger.AttributeMetaData;
-
-/**
- * {@link StyledLayerInterface} which contains a {@link FeatureSource} as geo object.<br>
- */
-public interface StyledFeatureSourceInterface extends StyledFeaturesInterface<FeatureSource> {
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package skrueger.geotools;
+
+import java.util.Map;
+
+import org.geotools.data.FeatureSource;
+
+import skrueger.AttributeMetaData;
+
+/**
+ * {@link StyledLayerInterface} which contains a {@link FeatureSource} as geo object.<br>
+ */
+public interface StyledFeatureSourceInterface extends StyledFeaturesInterface<FeatureSource> {
+
+}

Modified: trunk/src/skrueger/geotools/StyledFeaturesInterface.java
===================================================================
--- trunk/src/skrueger/geotools/StyledFeaturesInterface.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/StyledFeaturesInterface.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,3 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package skrueger.geotools;
 
 import java.util.Map;

Modified: trunk/src/skrueger/geotools/StyledGridCoverage.java
===================================================================
--- trunk/src/skrueger/geotools/StyledGridCoverage.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/StyledGridCoverage.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,228 +1,257 @@
-package skrueger.geotools;
-
-import java.net.URL;
-
-import javax.swing.ImageIcon;
-
-import org.geotools.coverage.grid.GridCoverage2D;
-import org.geotools.styling.Style;
-
-import schmitzm.geotools.JTSUtil;
-import schmitzm.geotools.grid.GridUtil;
-import skrueger.RasterLegendData;
-import skrueger.i8n.Translation;
-
-/**
- * This class provides a simple implementation of {@link StyledLayerInterface}
- * for {@link GridCoverage2D}. The uncache functionality is not supported,
- * because this class bases on an existing {@link GridCoverage2D} object in
- * memory.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class StyledGridCoverage extends AbstractStyledLayer<GridCoverage2D> implements StyledGridCoverageInterface {
-
-  /** Holds the meta data for displaying a legend. */
-  protected RasterLegendData legendData = null;
-
-  /**
-   * Creates a styled grid with language-specific informations.
-   * @param gc the grid
-   * @param id a unique ID for the object
-   * @param title a (language-specific) short description
-   * @param desc a (language-specific) long description
-   * @param keywords (language-specific) keywords for the geo objects
-   * @param style a display style (if {@code null}, a default style is created)
-   * @param legendData meta data for displaying a legend
-   * @param icon an icon for the object (can be {@code null})
-   * @exception IllegalArgumentException if {@code null} is given as ID or geo object
-   */
-  public StyledGridCoverage(GridCoverage2D gc, String id, Translation title, Translation desc, Translation keywords, Style style, RasterLegendData legendData, ImageIcon icon) {
-    super(gc, JTSUtil.createEnvelope(gc.getEnvelope()), gc.getCoordinateReferenceSystem(), id, title, desc, keywords, style, icon);
-    setLegendMetaData(legendData);
-  }
-
-  /**
-   * Creates a styled grid with language-specific informations.
-   * @param gc the grid
-   * @param id a unique ID for the object
-   * @param title a (language-specific) short description
-   * @param desc a (language-specific) long description
-   * @param keywords (language-specific) keywords for the geo objects
-   * @param style a display style with legend information
-   * @param icon an icon for the object (can be {@code null})
-   * @exception IllegalArgumentException if {@code null} is given as ID or geo object
-   */
-  public StyledGridCoverage(GridCoverage2D gc, String id, Translation title, Translation desc, Translation keywords, StyledLayerStyle<RasterLegendData> style, ImageIcon icon) {
-    super(gc, JTSUtil.createEnvelope(gc.getEnvelope()), gc.getCoordinateReferenceSystem(), id, title, desc, keywords, style != null ? style.getGeoObjectStyle() : null, icon);
-    setLegendMetaData( style != null ? style.getMetaData() : null );
-  }
-
-  /**
-   * Creates a styled grid with a language-specific title, no long description, no
-   * keywords and no icon.
-   * @param gc the grid
-   * @param id a unique ID for the object
-   * @param title a short description
-   * @param style a display style (if {@code null}, a default style is created)
-   * @param legendData meta data for displaying a legend
-   * @exception IllegalArgumentException if {@code null} is given as ID or geo object
-   */
-  public StyledGridCoverage(GridCoverage2D gc, String id, Translation title, Style style, RasterLegendData legendData) {
-    this(gc, id, title, null, null, style, legendData, null);
-  }
-
-  /**
-   * Creates a styled grid with non-translated informations.
-   * @param gc the grid
-   * @param id a unique ID for the object
-   * @param title a short description
-   * @param desc a long description
-   * @param keywords keywords for the geo objects
-   * @param style a display style (if {@code null}, a default style is created)
-   * @param legendData meta data for displaying a legend
-   * @param icon an icon for the object (can be {@code null})
-   * @exception IllegalArgumentException if {@code null} is given as ID or geo object
-   */
-  public StyledGridCoverage(GridCoverage2D gc, String id, String title, String desc, String keywords, Style style, RasterLegendData legendData, ImageIcon icon) {
-    this(gc, id, (Translation)null, null, null, style, legendData, icon);
-    setTitle(title);
-    setDesc(desc);
-    setKeywords(keywords);
-  }
-
-  /**
-   * Creates a styled grid with non-translated informations.
-   * @param gc the grid
-   * @param id a unique ID for the object
-   * @param title a short description
-   * @param desc a long description
-   * @param keywords keywords for the geo objects
-   * @param style a display style with legend information
-   * @param icon an icon for the object (can be {@code null})
-   * @exception IllegalArgumentException if {@code null} is given as ID or geo object
-   */
-  public StyledGridCoverage(GridCoverage2D gc, String id, String title, String desc, String keywords, StyledLayerStyle<RasterLegendData> style, ImageIcon icon) {
-    this(gc,
-         id,
-         title,
-         desc,
-         keywords,
-         style != null ? style.getGeoObjectStyle() : null,
-         style != null ? style.getMetaData() : null,
-         icon
-    );
-  }
-
-  /**
-   * Creates a styled grid with a non-translated title, no long description, no
-   * keywords and no icon.
-   * @param gc the grid
-   * @param id a unique ID for the object
-   * @param title a short description
-   * @param style a display style (if {@code null}, a default style is created)
-   * @exception IllegalArgumentException if {@code null} is given as ID or geo object
-   */
-  public StyledGridCoverage(GridCoverage2D gc, String id, String title, Style style, RasterLegendData legendData) {
-    this(gc, id, title, null, null, style, legendData, null);
-  }
-
-  /**
-   * Creates a styled grid with a non-translated title, no long description, no
-   * keywords and no icon.
-   * @param gc the grid
-   * @param id a unique ID for the object
-   * @param title a short description
-   * @param style a display style with legend information
-   * @exception IllegalArgumentException if {@code null} is given as ID or geo object
-   */
-  public StyledGridCoverage(GridCoverage2D gc, String id, String title, StyledLayerStyle<RasterLegendData> style) {
-    this(gc,
-         id,
-         title,
-         null,
-         null,
-         style != null ? style.getGeoObjectStyle() : null,
-         style != null ? style.getMetaData() : null,
-         null
-    );
-  }
-
-  /**
-   * Creates a default style for a {@link GridCoverage2D}.
-   * @see GridUtil#createDefaultStyle()
-   */
-  protected Style createDefaultStyle() {
-    return GridUtil.createDefaultStyle();
-  }
-
-  /**
-   * Returns the meta data needed for displaying a legend.
-   */
-  public RasterLegendData getLegendMetaData() {
-    return legendData;
-  }
-
-  /**
-   * Sets the meta data needed for displaying a legend.
-   * If {@code legendData} is {@code null} an empty {@link RasterLegendData}
-   * (without gaps) is set, so {@link #getLegendMetaData()} never returns {@code null}.
-   * @param legendData legend meta data
-   */
-  public void setLegendMetaData(RasterLegendData legendData) {
-    this.legendData = (legendData != null) ? legendData : new RasterLegendData(false);
-  }
-
-  /**
-   * Simply sets the {@link #geoObject}, {@link #crs}, {@link #envelope} and
-   * {@link #legendData} to {@code null}.
-   */
-  public void dispose() {
-    this.geoObject  = null;
-    this.envelope   = null;
-    this.crs        = null;
-    this.legendData = null;
-  }
-
-  /**
-   * Tests whether the geo object is disposed.
-   * @return boolean
-   */
-  public boolean isDisposed() {
-    return geoObject == null;
-  }
-
-  /**
-   * Does nothing, because the {@link AbstractStyledLayer} bases on existing
-   * objects (in memory) which can not be uncached and reloaded.
-   */
-  public void uncache() {
-    LOGGER.warn("Uncache functionality is not supported. Object remains in memory.");
-  }
-
-  /*
-   * (non-Javadoc)
-   * @see skrueger.geotools.StyledLayerInterface#getInfoURL()
-   */
-  public URL getInfoURL() {
-	return null;
-  }
-
-  /**
-	 * If true, this layer will not be shown in the legend. Default = false
-	 */
-	/**
-	 * 
-	 * Killed by SK: 6. April 09: Ein Layer soll nicht generell auf
-	 * verstecken/nicht verstecken gestellt werden können. Das sind
-	 * Eigenschaften der Karte/MapContext, ebenso wie die Reihenfolge der Layer.
-	 * Im Atlas verwaltet deshalb nun die Klasse skrueger.atlas.Map welche Layer
-	 * nicht in der Legende auftauchen sollen. Meines Wissens hat keiner bisher
-	 * die Funktion genutzt.
-	 * 
-  public boolean isHideInLegend() {
-	return false;
-   }
-	 */
-  
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package skrueger.geotools;
+
+import java.net.URL;
+
+import javax.swing.ImageIcon;
+
+import org.geotools.coverage.grid.GridCoverage2D;
+import org.geotools.styling.Style;
+
+import schmitzm.geotools.JTSUtil;
+import schmitzm.geotools.grid.GridUtil;
+import skrueger.RasterLegendData;
+import skrueger.i8n.Translation;
+
+/**
+ * This class provides a simple implementation of {@link StyledLayerInterface}
+ * for {@link GridCoverage2D}. The uncache functionality is not supported,
+ * because this class bases on an existing {@link GridCoverage2D} object in
+ * memory.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class StyledGridCoverage extends AbstractStyledLayer<GridCoverage2D> implements StyledGridCoverageInterface {
+
+  /** Holds the meta data for displaying a legend. */
+  protected RasterLegendData legendData = null;
+
+  /**
+   * Creates a styled grid with language-specific informations.
+   * @param gc the grid
+   * @param id a unique ID for the object
+   * @param title a (language-specific) short description
+   * @param desc a (language-specific) long description
+   * @param keywords (language-specific) keywords for the geo objects
+   * @param style a display style (if {@code null}, a default style is created)
+   * @param legendData meta data for displaying a legend
+   * @param icon an icon for the object (can be {@code null})
+   * @exception IllegalArgumentException if {@code null} is given as ID or geo object
+   */
+  public StyledGridCoverage(GridCoverage2D gc, String id, Translation title, Translation desc, Translation keywords, Style style, RasterLegendData legendData, ImageIcon icon) {
+    super(gc, JTSUtil.createEnvelope(gc.getEnvelope()), gc.getCoordinateReferenceSystem(), id, title, desc, keywords, style, icon);
+    setLegendMetaData(legendData);
+  }
+
+  /**
+   * Creates a styled grid with language-specific informations.
+   * @param gc the grid
+   * @param id a unique ID for the object
+   * @param title a (language-specific) short description
+   * @param desc a (language-specific) long description
+   * @param keywords (language-specific) keywords for the geo objects
+   * @param style a display style with legend information
+   * @param icon an icon for the object (can be {@code null})
+   * @exception IllegalArgumentException if {@code null} is given as ID or geo object
+   */
+  public StyledGridCoverage(GridCoverage2D gc, String id, Translation title, Translation desc, Translation keywords, StyledLayerStyle<RasterLegendData> style, ImageIcon icon) {
+    super(gc, JTSUtil.createEnvelope(gc.getEnvelope()), gc.getCoordinateReferenceSystem(), id, title, desc, keywords, style != null ? style.getGeoObjectStyle() : null, icon);
+    setLegendMetaData( style != null ? style.getMetaData() : null );
+  }
+
+  /**
+   * Creates a styled grid with a language-specific title, no long description, no
+   * keywords and no icon.
+   * @param gc the grid
+   * @param id a unique ID for the object
+   * @param title a short description
+   * @param style a display style (if {@code null}, a default style is created)
+   * @param legendData meta data for displaying a legend
+   * @exception IllegalArgumentException if {@code null} is given as ID or geo object
+   */
+  public StyledGridCoverage(GridCoverage2D gc, String id, Translation title, Style style, RasterLegendData legendData) {
+    this(gc, id, title, null, null, style, legendData, null);
+  }
+
+  /**
+   * Creates a styled grid with non-translated informations.
+   * @param gc the grid
+   * @param id a unique ID for the object
+   * @param title a short description
+   * @param desc a long description
+   * @param keywords keywords for the geo objects
+   * @param style a display style (if {@code null}, a default style is created)
+   * @param legendData meta data for displaying a legend
+   * @param icon an icon for the object (can be {@code null})
+   * @exception IllegalArgumentException if {@code null} is given as ID or geo object
+   */
+  public StyledGridCoverage(GridCoverage2D gc, String id, String title, String desc, String keywords, Style style, RasterLegendData legendData, ImageIcon icon) {
+    this(gc, id, (Translation)null, null, null, style, legendData, icon);
+    setTitle(title);
+    setDesc(desc);
+    setKeywords(keywords);
+  }
+
+  /**
+   * Creates a styled grid with non-translated informations.
+   * @param gc the grid
+   * @param id a unique ID for the object
+   * @param title a short description
+   * @param desc a long description
+   * @param keywords keywords for the geo objects
+   * @param style a display style with legend information
+   * @param icon an icon for the object (can be {@code null})
+   * @exception IllegalArgumentException if {@code null} is given as ID or geo object
+   */
+  public StyledGridCoverage(GridCoverage2D gc, String id, String title, String desc, String keywords, StyledLayerStyle<RasterLegendData> style, ImageIcon icon) {
+    this(gc,
+         id,
+         title,
+         desc,
+         keywords,
+         style != null ? style.getGeoObjectStyle() : null,
+         style != null ? style.getMetaData() : null,
+         icon
+    );
+  }
+
+  /**
+   * Creates a styled grid with a non-translated title, no long description, no
+   * keywords and no icon.
+   * @param gc the grid
+   * @param id a unique ID for the object
+   * @param title a short description
+   * @param style a display style (if {@code null}, a default style is created)
+   * @exception IllegalArgumentException if {@code null} is given as ID or geo object
+   */
+  public StyledGridCoverage(GridCoverage2D gc, String id, String title, Style style, RasterLegendData legendData) {
+    this(gc, id, title, null, null, style, legendData, null);
+  }
+
+  /**
+   * Creates a styled grid with a non-translated title, no long description, no
+   * keywords and no icon.
+   * @param gc the grid
+   * @param id a unique ID for the object
+   * @param title a short description
+   * @param style a display style with legend information
+   * @exception IllegalArgumentException if {@code null} is given as ID or geo object
+   */
+  public StyledGridCoverage(GridCoverage2D gc, String id, String title, StyledLayerStyle<RasterLegendData> style) {
+    this(gc,
+         id,
+         title,
+         null,
+         null,
+         style != null ? style.getGeoObjectStyle() : null,
+         style != null ? style.getMetaData() : null,
+         null
+    );
+  }
+
+  /**
+   * Creates a default style for a {@link GridCoverage2D}.
+   * @see GridUtil#createDefaultStyle()
+   */
+  protected Style createDefaultStyle() {
+    return GridUtil.createDefaultStyle();
+  }
+
+  /**
+   * Returns the meta data needed for displaying a legend.
+   */
+  public RasterLegendData getLegendMetaData() {
+    return legendData;
+  }
+
+  /**
+   * Sets the meta data needed for displaying a legend.
+   * If {@code legendData} is {@code null} an empty {@link RasterLegendData}
+   * (without gaps) is set, so {@link #getLegendMetaData()} never returns {@code null}.
+   * @param legendData legend meta data
+   */
+  public void setLegendMetaData(RasterLegendData legendData) {
+    this.legendData = (legendData != null) ? legendData : new RasterLegendData(false);
+  }
+
+  /**
+   * Simply sets the {@link #geoObject}, {@link #crs}, {@link #envelope} and
+   * {@link #legendData} to {@code null}.
+   */
+  public void dispose() {
+    this.geoObject  = null;
+    this.envelope   = null;
+    this.crs        = null;
+    this.legendData = null;
+  }
+
+  /**
+   * Tests whether the geo object is disposed.
+   * @return boolean
+   */
+  public boolean isDisposed() {
+    return geoObject == null;
+  }
+
+  /**
+   * Does nothing, because the {@link AbstractStyledLayer} bases on existing
+   * objects (in memory) which can not be uncached and reloaded.
+   */
+  public void uncache() {
+    LOGGER.warn("Uncache functionality is not supported. Object remains in memory.");
+  }
+
+  /*
+   * (non-Javadoc)
+   * @see skrueger.geotools.StyledLayerInterface#getInfoURL()
+   */
+  public URL getInfoURL() {
+	return null;
+  }
+
+  /**
+	 * If true, this layer will not be shown in the legend. Default = false
+	 */
+	/**
+	 * 
+	 * Killed by SK: 6. April 09: Ein Layer soll nicht generell auf
+	 * verstecken/nicht verstecken gestellt werden können. Das sind
+	 * Eigenschaften der Karte/MapContext, ebenso wie die Reihenfolge der Layer.
+	 * Im Atlas verwaltet deshalb nun die Klasse skrueger.atlas.Map welche Layer
+	 * nicht in der Legende auftauchen sollen. Meines Wissens hat keiner bisher
+	 * die Funktion genutzt.
+	 * 
+  public boolean isHideInLegend() {
+	return false;
+   }
+	 */
+  
+}

Modified: trunk/src/skrueger/geotools/StyledGridCoverageInterface.java
===================================================================
--- trunk/src/skrueger/geotools/StyledGridCoverageInterface.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/StyledGridCoverageInterface.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,10 +1,39 @@
-package skrueger.geotools;
-import org.geotools.coverage.grid.GridCoverage2D;
-
-/**
- * A {@link StyledRasterInterface} that is typed to wrap a {@link GridCoverage2D}
- * 
- * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
- */
-public interface StyledGridCoverageInterface extends StyledRasterInterface<GridCoverage2D>{
-};
\ No newline at end of file
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package skrueger.geotools;
+import org.geotools.coverage.grid.GridCoverage2D;
+
+/**
+ * A {@link StyledRasterInterface} that is typed to wrap a {@link GridCoverage2D}
+ * 
+ * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
+ */
+public interface StyledGridCoverageInterface extends StyledRasterInterface<GridCoverage2D>{
+};

Modified: trunk/src/skrueger/geotools/StyledGridCoverageReader.java
===================================================================
--- trunk/src/skrueger/geotools/StyledGridCoverageReader.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/StyledGridCoverageReader.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,229 +1,258 @@
-package skrueger.geotools;
-
-import java.net.URL;
-
-import javax.swing.ImageIcon;
-
-import org.geotools.coverage.grid.GridCoverage2D;
-import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader;
-import org.geotools.styling.Style;
-
-import schmitzm.geotools.JTSUtil;
-import schmitzm.geotools.grid.GridUtil;
-import skrueger.RasterLegendData;
-import skrueger.i8n.Translation;
-
-/**
- * This class provides a simple implementation of {@link StyledLayerInterface}
- * for {@link AbstractGridCoverage2DReader}. The uncache functionality is not supported,
- * because if the coverage is read once this class bases on an existing {@link GridCoverage2D}
- * object in memory.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class StyledGridCoverageReader extends AbstractStyledLayer<AbstractGridCoverage2DReader> implements StyledGridCoverageReaderInterface {
-
-  /** Holds the meta data for displaying a legend. */
-  protected RasterLegendData legendData = null;
-
-  /**
-   * Creates a styled grid with language-specific informations.
-   * @param gcr the grid reader
-   * @param id a unique ID for the object
-   * @param title a (language-specific) short description
-   * @param desc a (language-specific) long description
-   * @param keywords (language-specific) keywords for the geo objects
-   * @param style a display style (if {@code null}, a default style is created)
-   * @param legendData meta data for displaying a legend
-   * @param icon an icon for the object (can be {@code null})
-   * @exception IllegalArgumentException if {@code null} is given as ID or geo object
-   */
-  public StyledGridCoverageReader(AbstractGridCoverage2DReader gcr, String id, Translation title, Translation desc, Translation keywords, Style style, RasterLegendData legendData, ImageIcon icon) {
-    super(gcr, JTSUtil.createEnvelope(gcr.getOriginalEnvelope()), gcr.getCrs(), id, title, desc, keywords, style, icon);
-    setLegendMetaData(legendData);
-  }
-
-  /**
-   * Creates a styled grid with language-specific informations.
-   * @param gcr the grid reader
-   * @param id a unique ID for the object
-   * @param title a (language-specific) short description
-   * @param desc a (language-specific) long description
-   * @param keywords (language-specific) keywords for the geo objects
-   * @param style a display style with legend information
-   * @param icon an icon for the object (can be {@code null})
-   * @exception IllegalArgumentException if {@code null} is given as ID or geo object
-   */
-  public StyledGridCoverageReader(AbstractGridCoverage2DReader gcr, String id, Translation title, Translation desc, Translation keywords, StyledLayerStyle<RasterLegendData> style, ImageIcon icon) {
-    super(gcr, JTSUtil.createEnvelope(gcr.getOriginalEnvelope()), gcr.getCrs(), id, title, desc, keywords, style != null ? style.getGeoObjectStyle() : null, icon);
-    setLegendMetaData( style != null ? style.getMetaData() : null );
-  }
-
-  /**
-   * Creates a styled grid with a language-specific title, no long description, no
-   * keywords and no icon.
-   * @param gcr the grid reader
-   * @param id a unique ID for the object
-   * @param title a short description
-   * @param style a display style (if {@code null}, a default style is created)
-   * @param legendData meta data for displaying a legend
-   * @exception IllegalArgumentException if {@code null} is given as ID or geo object
-   */
-  public StyledGridCoverageReader(AbstractGridCoverage2DReader gcr, String id, Translation title, Style style, RasterLegendData legendData) {
-    this(gcr, id, title, null, null, style, legendData, null);
-  }
-
-  /**
-   * Creates a styled grid with non-translated informations.
-   * @param gcr the grid reader
-   * @param id a unique ID for the object
-   * @param title a short description
-   * @param desc a long description
-   * @param keywords keywords for the geo objects
-   * @param style a display style (if {@code null}, a default style is created)
-   * @param legendData meta data for displaying a legend
-   * @param icon an icon for the object (can be {@code null})
-   * @exception IllegalArgumentException if {@code null} is given as ID or geo object
-   */
-  public StyledGridCoverageReader(AbstractGridCoverage2DReader gcr, String id, String title, String desc, String keywords, Style style, RasterLegendData legendData, ImageIcon icon) {
-    this(gcr, id, (Translation)null, null, null, style, legendData, icon);
-    setTitle(title);
-    setDesc(desc);
-    setKeywords(keywords);
-  }
-
-  /**
-   * Creates a styled grid with non-translated informations.
-   * @param gcr the grid reader
-   * @param id a unique ID for the object
-   * @param title a short description
-   * @param desc a long description
-   * @param keywords keywords for the geo objects
-   * @param style a display style with legend information
-   * @param icon an icon for the object (can be {@code null})
-   * @exception IllegalArgumentException if {@code null} is given as ID or geo object
-   */
-  public StyledGridCoverageReader(AbstractGridCoverage2DReader gcr, String id, String title, String desc, String keywords, StyledLayerStyle<RasterLegendData> style, ImageIcon icon) {
-    this(gcr,
-         id,
-         title,
-         desc,
-         keywords,
-         style != null ? style.getGeoObjectStyle() : null,
-         style != null ? style.getMetaData() : null,
-         icon
-    );
-  }
-
-  /**
-   * Creates a styled grid with a non-translated title, no long description, no
-   * keywords and no icon.
-   * @param gcr the grid reader
-   * @param id a unique ID for the object
-   * @param title a short description
-   * @param style a display style (if {@code null}, a default style is created)
-   * @exception IllegalArgumentException if {@code null} is given as ID or geo object
-   */
-  public StyledGridCoverageReader(AbstractGridCoverage2DReader gcr, String id, String title, Style style, RasterLegendData legendData) {
-    this(gcr, id, title, null, null, style, legendData, null);
-  }
-
-  /**
-   * Creates a styled grid with a non-translated title, no long description, no
-   * keywords and no icon.
-   * @param gcr the grid reader
-   * @param id a unique ID for the object
-   * @param title a short description
-   * @param style a display style with legend information
-   * @exception IllegalArgumentException if {@code null} is given as ID or geo object
-   */
-  public StyledGridCoverageReader(AbstractGridCoverage2DReader gcr, String id, String title, StyledLayerStyle<RasterLegendData> style) {
-    this(gcr,
-         id,
-         title,
-         null,
-         null,
-         style != null ? style.getGeoObjectStyle() : null,
-         style != null ? style.getMetaData() : null,
-         null
-    );
-  }
-
-  /**
-   * Creates a default style for a {@link GridCoverage2D}.
-   * @see GridUtil#createDefaultStyle()
-   */
-  protected Style createDefaultStyle() {
-    return GridUtil.createDefaultStyle();
-  }
-
-  /**
-   * Returns the meta data needed for displaying a legend.
-   */
-  public RasterLegendData getLegendMetaData() {
-    return legendData;
-  }
-
-  /**
-   * Sets the meta data needed for displaying a legend.
-   * If {@code legendData} is {@code null} an empty {@link RasterLegendData}
-   * (without gaps) is set, so {@link #getLegendMetaData()} never returns {@code null}.
-   * @param legendData legend meta data
-   */
-  public void setLegendMetaData(RasterLegendData legendData) {
-    this.legendData = (legendData != null) ? legendData : new RasterLegendData(false);
-  }
-
-  /**
-   * Simply sets the {@link #geoObject}, {@link #crs}, {@link #envelope} and
-   * {@link #legendData} to {@code null}.
-   */
-  public void dispose() {
-    this.geoObject  = null;
-    this.envelope   = null;
-    this.crs        = null;
-    this.legendData = null;
-  }
-
-  /**
-   * Tests whether the geo object is disposed.
-   * @return boolean
-   */
-  public boolean isDisposed() {
-    return geoObject == null;
-  }
-
-  /**
-   * Does nothing, because the {@link AbstractStyledLayer} bases on existing
-   * objects (in memory) which can not be uncached and reloaded.
-   */
-  public void uncache() {
-    LOGGER.warn("Uncache functionality is not supported. Object remains in memory.");
-  }
-
-  /*
-   * (non-Javadoc)
-   * @see skrueger.geotools.StyledLayerInterface#getInfoURL()
-   */
-  public URL getInfoURL() {
-    return null;
-  }
-
-  /**
-	 * If true, this layer will not be shown in the legend. Default = false
-	 */
-	/**
-	 * 
-	 * Killed by SK: 6. April 09: Ein Layer soll nicht generell auf
-	 * verstecken/nicht verstecken gestellt werden können. Das sind
-	 * Eigenschaften der Karte/MapContext, ebenso wie die Reihenfolge der Layer.
-	 * Im Atlas verwaltet deshalb nun die Klasse skrueger.atlas.Map welche Layer
-	 * nicht in der Legende auftauchen sollen. Meines Wissens hat keiner bisher
-	 * die Funktion genutzt.
-	 * 
-  public boolean isHideInLegend() {
-    return false;
-  }
-	 */
-  
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package skrueger.geotools;
+
+import java.net.URL;
+
+import javax.swing.ImageIcon;
+
+import org.geotools.coverage.grid.GridCoverage2D;
+import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader;
+import org.geotools.styling.Style;
+
+import schmitzm.geotools.JTSUtil;
+import schmitzm.geotools.grid.GridUtil;
+import skrueger.RasterLegendData;
+import skrueger.i8n.Translation;
+
+/**
+ * This class provides a simple implementation of {@link StyledLayerInterface}
+ * for {@link AbstractGridCoverage2DReader}. The uncache functionality is not supported,
+ * because if the coverage is read once this class bases on an existing {@link GridCoverage2D}
+ * object in memory.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class StyledGridCoverageReader extends AbstractStyledLayer<AbstractGridCoverage2DReader> implements StyledGridCoverageReaderInterface {
+
+  /** Holds the meta data for displaying a legend. */
+  protected RasterLegendData legendData = null;
+
+  /**
+   * Creates a styled grid with language-specific informations.
+   * @param gcr the grid reader
+   * @param id a unique ID for the object
+   * @param title a (language-specific) short description
+   * @param desc a (language-specific) long description
+   * @param keywords (language-specific) keywords for the geo objects
+   * @param style a display style (if {@code null}, a default style is created)
+   * @param legendData meta data for displaying a legend
+   * @param icon an icon for the object (can be {@code null})
+   * @exception IllegalArgumentException if {@code null} is given as ID or geo object
+   */
+  public StyledGridCoverageReader(AbstractGridCoverage2DReader gcr, String id, Translation title, Translation desc, Translation keywords, Style style, RasterLegendData legendData, ImageIcon icon) {
+    super(gcr, JTSUtil.createEnvelope(gcr.getOriginalEnvelope()), gcr.getCrs(), id, title, desc, keywords, style, icon);
+    setLegendMetaData(legendData);
+  }
+
+  /**
+   * Creates a styled grid with language-specific informations.
+   * @param gcr the grid reader
+   * @param id a unique ID for the object
+   * @param title a (language-specific) short description
+   * @param desc a (language-specific) long description
+   * @param keywords (language-specific) keywords for the geo objects
+   * @param style a display style with legend information
+   * @param icon an icon for the object (can be {@code null})
+   * @exception IllegalArgumentException if {@code null} is given as ID or geo object
+   */
+  public StyledGridCoverageReader(AbstractGridCoverage2DReader gcr, String id, Translation title, Translation desc, Translation keywords, StyledLayerStyle<RasterLegendData> style, ImageIcon icon) {
+    super(gcr, JTSUtil.createEnvelope(gcr.getOriginalEnvelope()), gcr.getCrs(), id, title, desc, keywords, style != null ? style.getGeoObjectStyle() : null, icon);
+    setLegendMetaData( style != null ? style.getMetaData() : null );
+  }
+
+  /**
+   * Creates a styled grid with a language-specific title, no long description, no
+   * keywords and no icon.
+   * @param gcr the grid reader
+   * @param id a unique ID for the object
+   * @param title a short description
+   * @param style a display style (if {@code null}, a default style is created)
+   * @param legendData meta data for displaying a legend
+   * @exception IllegalArgumentException if {@code null} is given as ID or geo object
+   */
+  public StyledGridCoverageReader(AbstractGridCoverage2DReader gcr, String id, Translation title, Style style, RasterLegendData legendData) {
+    this(gcr, id, title, null, null, style, legendData, null);
+  }
+
+  /**
+   * Creates a styled grid with non-translated informations.
+   * @param gcr the grid reader
+   * @param id a unique ID for the object
+   * @param title a short description
+   * @param desc a long description
+   * @param keywords keywords for the geo objects
+   * @param style a display style (if {@code null}, a default style is created)
+   * @param legendData meta data for displaying a legend
+   * @param icon an icon for the object (can be {@code null})
+   * @exception IllegalArgumentException if {@code null} is given as ID or geo object
+   */
+  public StyledGridCoverageReader(AbstractGridCoverage2DReader gcr, String id, String title, String desc, String keywords, Style style, RasterLegendData legendData, ImageIcon icon) {
+    this(gcr, id, (Translation)null, null, null, style, legendData, icon);
+    setTitle(title);
+    setDesc(desc);
+    setKeywords(keywords);
+  }
+
+  /**
+   * Creates a styled grid with non-translated informations.
+   * @param gcr the grid reader
+   * @param id a unique ID for the object
+   * @param title a short description
+   * @param desc a long description
+   * @param keywords keywords for the geo objects
+   * @param style a display style with legend information
+   * @param icon an icon for the object (can be {@code null})
+   * @exception IllegalArgumentException if {@code null} is given as ID or geo object
+   */
+  public StyledGridCoverageReader(AbstractGridCoverage2DReader gcr, String id, String title, String desc, String keywords, StyledLayerStyle<RasterLegendData> style, ImageIcon icon) {
+    this(gcr,
+         id,
+         title,
+         desc,
+         keywords,
+         style != null ? style.getGeoObjectStyle() : null,
+         style != null ? style.getMetaData() : null,
+         icon
+    );
+  }
+
+  /**
+   * Creates a styled grid with a non-translated title, no long description, no
+   * keywords and no icon.
+   * @param gcr the grid reader
+   * @param id a unique ID for the object
+   * @param title a short description
+   * @param style a display style (if {@code null}, a default style is created)
+   * @exception IllegalArgumentException if {@code null} is given as ID or geo object
+   */
+  public StyledGridCoverageReader(AbstractGridCoverage2DReader gcr, String id, String title, Style style, RasterLegendData legendData) {
+    this(gcr, id, title, null, null, style, legendData, null);
+  }
+
+  /**
+   * Creates a styled grid with a non-translated title, no long description, no
+   * keywords and no icon.
+   * @param gcr the grid reader
+   * @param id a unique ID for the object
+   * @param title a short description
+   * @param style a display style with legend information
+   * @exception IllegalArgumentException if {@code null} is given as ID or geo object
+   */
+  public StyledGridCoverageReader(AbstractGridCoverage2DReader gcr, String id, String title, StyledLayerStyle<RasterLegendData> style) {
+    this(gcr,
+         id,
+         title,
+         null,
+         null,
+         style != null ? style.getGeoObjectStyle() : null,
+         style != null ? style.getMetaData() : null,
+         null
+    );
+  }
+
+  /**
+   * Creates a default style for a {@link GridCoverage2D}.
+   * @see GridUtil#createDefaultStyle()
+   */
+  protected Style createDefaultStyle() {
+    return GridUtil.createDefaultStyle();
+  }
+
+  /**
+   * Returns the meta data needed for displaying a legend.
+   */
+  public RasterLegendData getLegendMetaData() {
+    return legendData;
+  }
+
+  /**
+   * Sets the meta data needed for displaying a legend.
+   * If {@code legendData} is {@code null} an empty {@link RasterLegendData}
+   * (without gaps) is set, so {@link #getLegendMetaData()} never returns {@code null}.
+   * @param legendData legend meta data
+   */
+  public void setLegendMetaData(RasterLegendData legendData) {
+    this.legendData = (legendData != null) ? legendData : new RasterLegendData(false);
+  }
+
+  /**
+   * Simply sets the {@link #geoObject}, {@link #crs}, {@link #envelope} and
+   * {@link #legendData} to {@code null}.
+   */
+  public void dispose() {
+    this.geoObject  = null;
+    this.envelope   = null;
+    this.crs        = null;
+    this.legendData = null;
+  }
+
+  /**
+   * Tests whether the geo object is disposed.
+   * @return boolean
+   */
+  public boolean isDisposed() {
+    return geoObject == null;
+  }
+
+  /**
+   * Does nothing, because the {@link AbstractStyledLayer} bases on existing
+   * objects (in memory) which can not be uncached and reloaded.
+   */
+  public void uncache() {
+    LOGGER.warn("Uncache functionality is not supported. Object remains in memory.");
+  }
+
+  /*
+   * (non-Javadoc)
+   * @see skrueger.geotools.StyledLayerInterface#getInfoURL()
+   */
+  public URL getInfoURL() {
+    return null;
+  }
+
+  /**
+	 * If true, this layer will not be shown in the legend. Default = false
+	 */
+	/**
+	 * 
+	 * Killed by SK: 6. April 09: Ein Layer soll nicht generell auf
+	 * verstecken/nicht verstecken gestellt werden können. Das sind
+	 * Eigenschaften der Karte/MapContext, ebenso wie die Reihenfolge der Layer.
+	 * Im Atlas verwaltet deshalb nun die Klasse skrueger.atlas.Map welche Layer
+	 * nicht in der Legende auftauchen sollen. Meines Wissens hat keiner bisher
+	 * die Funktion genutzt.
+	 * 
+  public boolean isHideInLegend() {
+    return false;
+  }
+	 */
+  
+}

Modified: trunk/src/skrueger/geotools/StyledGridCoverageReaderInterface.java
===================================================================
--- trunk/src/skrueger/geotools/StyledGridCoverageReaderInterface.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/StyledGridCoverageReaderInterface.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,10 +1,39 @@
-package skrueger.geotools;
-import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader;
-
-/**
- * A {@link StyledRasterInterface} that is typed to wrap a {@link AbstractGridCoverage2DReader}
- * 
- * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
- */
-public interface StyledGridCoverageReaderInterface extends StyledRasterInterface<AbstractGridCoverage2DReader>{
-};
\ No newline at end of file
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package skrueger.geotools;
+import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader;
+
+/**
+ * A {@link StyledRasterInterface} that is typed to wrap a {@link AbstractGridCoverage2DReader}
+ * 
+ * @author <a href="mailto:Martin.Schmitz at koeln.de">Martin Schmitz</a>
+ */
+public interface StyledGridCoverageReaderInterface extends StyledRasterInterface<AbstractGridCoverage2DReader>{
+};

Modified: trunk/src/skrueger/geotools/StyledLayerInterface.java
===================================================================
--- trunk/src/skrueger/geotools/StyledLayerInterface.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/StyledLayerInterface.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,132 +1,161 @@
-package skrueger.geotools;
-
-import java.net.URL;
-
-import javax.swing.ImageIcon;
-
-import org.geotools.feature.FeatureCollection;
-import org.geotools.styling.Style;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-
-import skrueger.AttributeMetaData;
-import skrueger.RasterLegendData;
-import skrueger.i8n.Translation;
-
-import com.vividsolutions.jts.geom.Envelope;
-
-/**
- * This class is the top interface for styled objects to be managed in
- * {@link MapContextManagerInterface}. The (rough) classe structure is the
- * following:
- * <ul>
- * <li><b>{@link StyledLayerInterface StyledLayerInterface<E>}</b>
- * <ul>
- * <li>{@link #getId()} -> String</li>
- * <li>{@link #getKeywords() get/setKeywords()} -> {@link Translation}</li>
- * <li>{@link #getTitle() set/getTitle()} -> {@link Translation} (short
- * description for layer list)</li>
- * <li>{@link #getDesc() set/getDesc()} -> {@link Translation} (long description
- * for details)</li>
- * <li>{@link #getCrs()} -> {@link CoordinateReferenceSystem}</li>
- * <li>{@link #getCRSString()} -> String (readable description of CRS)</li>
- * <li>{@link #getEnvelope()} -> {@link Envelope} (JTS-Envelope)</li>
- * <li>{@link #getGeoObject()} -> E (GridCoverage/FeatureCollection/...)</li>
- * <li>{@link #getStyle() set/getStyle()} -> {@link Style}</li>
- * <li>{@link #uncache()}</li>
- * <li>{@link #dispose()}</li>
- * </ul>
- * </li>
- * <li><b>{@link StyledFeatureCollectionInterface} extends
- * {@link StyledLayerInterface StyledLayerInterface<FeatureCollection>}</b>
- * <ul>
- * <li>{@link StyledFeatureCollectionInterface#getAttributeMetaDataMap()} ->
- * Map<Integer,AttributeMetaData></li>
- * </ul>
- * </li>
- * <li><b>{@link StyledRasterInterface} extends {@link StyledLayerInterface
- * StyledLayerInterface<GridCoverage2D>}</b>
- * <ul>
- * <li>{@link StyledRasterInterface#getLegendMetaData()} ->
- * {@link RasterLegendData}</li>
- * </ul>
- * </li>
- * </ul>
- * <br>
- * <b>Restrictions:</b>
- * <ul>
- * <li>layer list only depends on {@link StyledLayerInterface}</li>
- * <li>methods returning {@link Translation} must not return {@code null}</li>
- * <li>methods returning {@link AttributeMetaData}-Map must not return {@code
- * null}</li>
- * <li>static helper method to get a new {@link AttributeMetaData}-map withe the
- * visible attributes only</li>
- * <li>static helper method to create a "default" {@link AttributeMetaData}-map
- * for a {@link FeatureCollection} with all attributes visible and without real
- * translations, but the attribute name as description.</li>
- * </ul>
- */
-public interface StyledLayerInterface<E> {
-	public String getId();
-
-	public Translation getTitle();
-
-	public void setTitle(Translation title);
-
-	public Translation getDesc();
-
-	public void setDesc(Translation dec);
-
-	public Translation getKeywords();
-
-	public void setKeywords(Translation keywords);
-
-	public CoordinateReferenceSystem getCrs();
-
-	public String getCRSString();
-
-	public Envelope getEnvelope();
-
-	/**
-	 * @return return an ImageIcon - <code>null</code> is valid and no icon or a
-	 *         default icon will then be shown
-	 */
-	public ImageIcon getImageIcon();
-
-	public void setImageIcon(ImageIcon icon);
-
-	/**
-	 * Returns the underlying GeoTools Object
-	 * 
-	 * @throws RuntimeException
-	 */
-	public E getGeoObject();
-
-	public Style getStyle();
-
-	public void setStyle(Style style);
-
-	/**
-	 * Returns the {@link URL} to a (HTML) file that provides more information
-	 * about this layer. If no HTML if associated with this
-	 * {@link StyledLayerInterface}, then <code>null</code> will be returned.
-	 * 
-	 * @return null or an {@link URL}
-	 */
-	public URL getInfoURL();
-
-	/**
-	 * Should be called when this Object is not needed anymore.
-	 */
-	public void dispose();
-
-	/** Is the object already disposed? * */
-	public boolean isDisposed();
-
-	/**
-	 * Clears any caches. For example the GeoObject could be released, and
-	 * reread on next call of getGeoObject()
-	 */
-	public void uncache();
-
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package skrueger.geotools;
+
+import java.net.URL;
+
+import javax.swing.ImageIcon;
+
+import org.geotools.feature.FeatureCollection;
+import org.geotools.styling.Style;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+
+import skrueger.AttributeMetaData;
+import skrueger.RasterLegendData;
+import skrueger.i8n.Translation;
+
+import com.vividsolutions.jts.geom.Envelope;
+
+/**
+ * This class is the top interface for styled objects to be managed in
+ * {@link MapContextManagerInterface}. The (rough) classe structure is the
+ * following:
+ * <ul>
+ * <li><b>{@link StyledLayerInterface StyledLayerInterface<E>}</b>
+ * <ul>
+ * <li>{@link #getId()} -> String</li>
+ * <li>{@link #getKeywords() get/setKeywords()} -> {@link Translation}</li>
+ * <li>{@link #getTitle() set/getTitle()} -> {@link Translation} (short
+ * description for layer list)</li>
+ * <li>{@link #getDesc() set/getDesc()} -> {@link Translation} (long description
+ * for details)</li>
+ * <li>{@link #getCrs()} -> {@link CoordinateReferenceSystem}</li>
+ * <li>{@link #getCRSString()} -> String (readable description of CRS)</li>
+ * <li>{@link #getEnvelope()} -> {@link Envelope} (JTS-Envelope)</li>
+ * <li>{@link #getGeoObject()} -> E (GridCoverage/FeatureCollection/...)</li>
+ * <li>{@link #getStyle() set/getStyle()} -> {@link Style}</li>
+ * <li>{@link #uncache()}</li>
+ * <li>{@link #dispose()}</li>
+ * </ul>
+ * </li>
+ * <li><b>{@link StyledFeatureCollectionInterface} extends
+ * {@link StyledLayerInterface StyledLayerInterface<FeatureCollection>}</b>
+ * <ul>
+ * <li>{@link StyledFeatureCollectionInterface#getAttributeMetaDataMap()} ->
+ * Map<Integer,AttributeMetaData></li>
+ * </ul>
+ * </li>
+ * <li><b>{@link StyledRasterInterface} extends {@link StyledLayerInterface
+ * StyledLayerInterface<GridCoverage2D>}</b>
+ * <ul>
+ * <li>{@link StyledRasterInterface#getLegendMetaData()} ->
+ * {@link RasterLegendData}</li>
+ * </ul>
+ * </li>
+ * </ul>
+ * <br>
+ * <b>Restrictions:</b>
+ * <ul>
+ * <li>layer list only depends on {@link StyledLayerInterface}</li>
+ * <li>methods returning {@link Translation} must not return {@code null}</li>
+ * <li>methods returning {@link AttributeMetaData}-Map must not return {@code
+ * null}</li>
+ * <li>static helper method to get a new {@link AttributeMetaData}-map withe the
+ * visible attributes only</li>
+ * <li>static helper method to create a "default" {@link AttributeMetaData}-map
+ * for a {@link FeatureCollection} with all attributes visible and without real
+ * translations, but the attribute name as description.</li>
+ * </ul>
+ */
+public interface StyledLayerInterface<E> {
+	public String getId();
+
+	public Translation getTitle();
+
+	public void setTitle(Translation title);
+
+	public Translation getDesc();
+
+	public void setDesc(Translation dec);
+
+	public Translation getKeywords();
+
+	public void setKeywords(Translation keywords);
+
+	public CoordinateReferenceSystem getCrs();
+
+	public String getCRSString();
+
+	public Envelope getEnvelope();
+
+	/**
+	 * @return return an ImageIcon - <code>null</code> is valid and no icon or a
+	 *         default icon will then be shown
+	 */
+	public ImageIcon getImageIcon();
+
+	public void setImageIcon(ImageIcon icon);
+
+	/**
+	 * Returns the underlying GeoTools Object
+	 * 
+	 * @throws RuntimeException
+	 */
+	public E getGeoObject();
+
+	public Style getStyle();
+
+	public void setStyle(Style style);
+
+	/**
+	 * Returns the {@link URL} to a (HTML) file that provides more information
+	 * about this layer. If no HTML if associated with this
+	 * {@link StyledLayerInterface}, then <code>null</code> will be returned.
+	 * 
+	 * @return null or an {@link URL}
+	 */
+	public URL getInfoURL();
+
+	/**
+	 * Should be called when this Object is not needed anymore.
+	 */
+	public void dispose();
+
+	/** Is the object already disposed? * */
+	public boolean isDisposed();
+
+	/**
+	 * Clears any caches. For example the GeoObject could be released, and
+	 * reread on next call of getGeoObject()
+	 */
+	public void uncache();
+
+
+}

Modified: trunk/src/skrueger/geotools/StyledLayerStyle.java
===================================================================
--- trunk/src/skrueger/geotools/StyledLayerStyle.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/StyledLayerStyle.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,58 +1,87 @@
-package skrueger.geotools;
-
-import org.geotools.styling.Style;
-
-/**
- * This class combines a Geotools visualisation {@link Style} with additional
- * meta data needed for visualisation (for example legend data).
- * The class {@code E} defines the type of the meta data.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class StyledLayerStyle<E> {
-  /** Holds the Geotools {@link Style} for the geo object visualisation. */
-  protected Style geoObjectStyle = null;
-  /** Holds the additional meta data for object visualisation (for example
-   *  legend information). */
-  protected E metaData = null;
-
-  /**
-   * Creates a new style for a {@link StyledLayerInterface}.
-   * @param style Style
-   * @param metaData E
-   */
-  public StyledLayerStyle(Style style, E metaData) {
-    setGeoObjectStyle(style);
-    setMetaData(metaData);
-  }
-
-  /**
-   * Returns the additional meta data needed for object visualisation.
-   */
-  public E getMetaData() {
-    return metaData;
-  }
-
-  /**
-   * Sets the additional meta data needed for object visualisation.
-   * @param metaData the meta data
-   */
-  public void setMetaData(E metaData) {
-    this.metaData = metaData;
-  }
-
-  /**
-   * Returns the Geotools style for the object visualisation.
-   */
-  public Style getGeoObjectStyle() {
-    return geoObjectStyle;
-  }
-
-  /**
-   * Sets the Geotools style for the object visualisation.
-   * @param style a Geotools visualisation style
-   */
-  public void setGeoObjectStyle(Style style) {
-    this.geoObjectStyle = style;
-  }
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package skrueger.geotools;
+
+import org.geotools.styling.Style;
+
+/**
+ * This class combines a Geotools visualisation {@link Style} with additional
+ * meta data needed for visualisation (for example legend data).
+ * The class {@code E} defines the type of the meta data.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class StyledLayerStyle<E> {
+  /** Holds the Geotools {@link Style} for the geo object visualisation. */
+  protected Style geoObjectStyle = null;
+  /** Holds the additional meta data for object visualisation (for example
+   *  legend information). */
+  protected E metaData = null;
+
+  /**
+   * Creates a new style for a {@link StyledLayerInterface}.
+   * @param style Style
+   * @param metaData E
+   */
+  public StyledLayerStyle(Style style, E metaData) {
+    setGeoObjectStyle(style);
+    setMetaData(metaData);
+  }
+
+  /**
+   * Returns the additional meta data needed for object visualisation.
+   */
+  public E getMetaData() {
+    return metaData;
+  }
+
+  /**
+   * Sets the additional meta data needed for object visualisation.
+   * @param metaData the meta data
+   */
+  public void setMetaData(E metaData) {
+    this.metaData = metaData;
+  }
+
+  /**
+   * Returns the Geotools style for the object visualisation.
+   */
+  public Style getGeoObjectStyle() {
+    return geoObjectStyle;
+  }
+
+  /**
+   * Sets the Geotools style for the object visualisation.
+   * @param style a Geotools visualisation style
+   */
+  public void setGeoObjectStyle(Style style) {
+    this.geoObjectStyle = style;
+  }
+}

Modified: trunk/src/skrueger/geotools/StyledLayerUtil.java
===================================================================
--- trunk/src/skrueger/geotools/StyledLayerUtil.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/StyledLayerUtil.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,699 +1,728 @@
-package skrueger.geotools;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileWriter;
-import java.net.URL;
-import java.text.DecimalFormat;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.SortedMap;
-import java.util.TreeMap;
-
-import org.apache.log4j.Logger;
-import org.geotools.coverage.grid.GridCoverage2D;
-import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader;
-import org.geotools.feature.FeatureCollection;
-import org.geotools.map.DefaultMapLayer;
-import org.geotools.map.MapLayer;
-import org.geotools.styling.ColorMap;
-import org.geotools.styling.ColorMapEntry;
-import org.geotools.styling.RasterSymbolizer;
-import org.geotools.styling.Style;
-import org.jdom.Document;
-import org.jdom.Element;
-import org.jdom.input.SAXBuilder;
-import org.jdom.output.XMLOutputter;
-
-import schmitzm.geotools.styling.StylingUtil;
-import schmitzm.io.IOUtil;
-import schmitzm.lang.LangUtil;
-import schmitzm.swing.SwingUtil;
-import skrueger.AttributeMetaData;
-import skrueger.RasterLegendData;
-import skrueger.i8n.Translation;
-
-/**
- * This class provides static helper methods for dealing with
- * {@link StyledLayerInterface} stuff.
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
- * @version 1.0
- */
-public class StyledLayerUtil {
-  private static final Logger LOGGER = Logger.getLogger(StyledLayerUtil.class.getName());
-  private static final SAXBuilder SAX_BUILDER = new SAXBuilder();
-  private static final XMLOutputter XML_OUTPUTTER = new XMLOutputter();
-
-  /** URL for Atlas XML schema */
-  public static final String AMLURI = "http://www.wikisquare.de/AtlasML";
-  /** Name of the XML Element for the attribute meta data map */
-  public static final String ELEM_NAME_AMD = "attributeMetaData";
-  /** Name of the XML Element for the raster legend data */
-  public static final String ELEM_NAME_RLD = "rasterLegendData";
-  /** Name of the XML Element for an attribute meta data map entry */
-  public static final String ELEM_NAME_ATTRIBUTE = "dataAttribute";
-  /** Name of the XML Element for an raster legend data entry */
-  public static final String ELEM_NAME_RASTERLEGEND = "rasterLegendItem";
-  /** Name of the XML Element for a translation */
-  public static final String ELEM_NAME_TRANSLATION = "translation";
-
-  /**
-   * Creates a Geotools {@link MapLayer} from an object. If the object is a
-   * {@link StyledLayerInterface} then its sytle is used. In case of direct
-   * Geotools objects ({@link GridCoverage2D}, {@link AbstractGridCoverage2DReader},
-   * {@link FeatureCollection}) a default style is generated.
-   * @param object an Object
-   * @exception Exception if {@code null} is given as object or an error occurs during layer creation
-   */
-  public static MapLayer createMapLayer(Object object) throws Exception {
-    return createMapLayer(object,null);
-  }
-
-  /**
-   * Creates a Geotools {@link MapLayer} from an object. If the object is a
-   * {@link StyledLayerInterface} then its sytle is used. In case of direct
-   * Geotools objects ({@link GridCoverage2D}, {@link AbstractGridCoverage2DReader},
-   * {@link FeatureCollection}) a default style is generated.
-   * @param object an Object
-   * @param forcedStyle (SLD-)Style to force for the object
-   * @exception Exception if {@code null} is given as object or an error occurs during layer creation
-   */
-  public static MapLayer createMapLayer(Object object, Style forcedStyle) throws Exception {
-    MapLayer layer     = null;
-    Style    style     = null;
-    if ( object instanceof StyledLayerInterface ) {
-      style =  ((StyledLayerInterface<?>)object).getStyle();
-      object = ((StyledLayerInterface<?>)object).getGeoObject();
-    }
-    if ( forcedStyle != null )
-      style = forcedStyle;
-    if ( style == null )
-      style = StylingUtil.createDefaultStyle(object);
-
-    if (object instanceof GridCoverage2D)
-      layer = new DefaultMapLayer( (GridCoverage2D) object, style);
-    if (object instanceof AbstractGridCoverage2DReader)
-      layer = new DefaultMapLayer( (AbstractGridCoverage2DReader) object, style);
-    if (object instanceof FeatureCollection)
-      layer = new DefaultMapLayer( (FeatureCollection) object, style);
-
-    if ( layer == null )
-      throw new Exception("Can not create MapLayer from "+(object == null ? "null" : object.getClass()));
-
-    return layer;
-  }
-
-  /**
-   * Creates an default instance of {@link StyledLayerInterface} for a Geotools
-   * object ({@link GridCoverage2D}, {@link FeatureCollection}) with a default
-   * style.
-   * @param object an Object
-   * @param title  title for the object
-   * @exception UnsupportedOperationException if {@code null} is given as object or an error occurs during creation
-   */
-  public static StyledLayerInterface<?> createStyledLayer(Object object, String title) {
-     return createStyledLayer(object, title, null);
-  }
-
-  /**
-   * Creates an default instance of {@link StyledLayerInterface} for a Geotools
-   * object ({@link GridCoverage2D}, {@link FeatureCollection}) with a given
-   * style.
-   * @param object an Object
-   * @param title  title for the object
-   * @param style  style and meta data for the object
-   * @exception UnsupportedOperationException if {@code null} is given as object or an error occurs during creation
-   */
-  public static StyledLayerInterface<?> createStyledLayer(Object object, String title, StyledLayerStyle style) {
-    StyledLayerInterface<?> styledLayer = null;
-
-    String id = (title != null) ? title : "defaultID";
-
-    if ( object instanceof GridCoverage2D )
-      styledLayer = new StyledGridCoverage(
-          (GridCoverage2D)object,
-          id,
-          title,
-          style
-      );
-    else if ( object instanceof AbstractGridCoverage2DReader )
-           styledLayer = new StyledGridCoverageReader(
-               (AbstractGridCoverage2DReader)object,
-               id,
-               title,
-               style
-           );
-    else if ( object instanceof FeatureCollection )
-      styledLayer = new StyledFeatureCollection(
-          (FeatureCollection)object,
-          id,
-          title,
-          style
-      );
-    
-    if ( styledLayer == null )
-      throw new UnsupportedOperationException("Can not create StyledLayerInterface object from "+(object == null ? "null" : object.getClass()));
-
-    return styledLayer;
-  }
-
-  /**
-   * Return only the visible or invisible entries of an AttributeMetaData-Map.
-   * @param amdMap AttributeMetaData-Map
-   * @param visible indicated whether the visible or invisible entries are
-   *                returned 
-   */
-  public static SortedMap<Integer,AttributeMetaData> getVisibleAttributeMetaData(Map<Integer,AttributeMetaData> amdMap, boolean visible) {
-    SortedMap<Integer,AttributeMetaData> filteredMap = new TreeMap<Integer,AttributeMetaData>();
-    for (AttributeMetaData amd : amdMap.values())
-      if ( amd.isVisible() )
-        filteredMap.put(amd.getColIdx(), amd);
-    
-    return filteredMap;
-  }
-  
-  
-  /**
-   * Parses a {@link AttributeMetaData} object from an JDOM-{@link Element}.
-   * This method works like {@link AMLImport#parseDataAttribute(org.w3c.dom.Node},
-   * but for JDOM.
-   * @param element {@link Element} to parse
-   */
-  public static AttributeMetaData parseAttributeMetaData(final Element element) {
-    final Integer col = Integer.valueOf(element.getAttributeValue("col"));
-    final Boolean visible = Boolean.valueOf(element.getAttributeValue("visible"));
-    final String unit = element.getAttributeValue("unit");
-
-    Translation name = new Translation();
-    Translation desc = new Translation();
-    for (final Element childElement : (List<Element>)element.getChildren()) {
-      if (childElement.getName() == null)
-        continue;
-
-      if (childElement.getName().equals("name"))
-        name = parseTranslation(childElement);
-      else if (childElement.getName().equals("desc"))
-        desc = parseTranslation(childElement);
-    }
-    return new AttributeMetaData(col, visible, name, desc, unit);
-  }
-
-  /**
-   * Parses a {@link AttributeMetaData} map from an JDOM-{@link Element}
-   * with {@code <attribute>}-childs.
-   * @param element {@link Element} to parse
-   */
-  public static Map<Integer,AttributeMetaData> parseAttributeMetaDataMap(final Element element) {
-    HashMap<Integer,AttributeMetaData> metaData = new HashMap<Integer,AttributeMetaData>();
-    List<Element> attributesElements = element.getChildren( ELEM_NAME_ATTRIBUTE );
-    for (Element attibuteElement : attributesElements)
-    {
-      AttributeMetaData attrMetaData = parseAttributeMetaData( attibuteElement );
-      metaData.put( attrMetaData.getColIdx(), attrMetaData );
-    }
-    return metaData;
-  }
-
-  /**
-   * Loads a {@link AttributeMetaData} object from an URL.
-   * @param documentUrl {@link URL} to parse
-   * @see #parseAttributeMetaData(Element)
-   */
-  public static Map<Integer,AttributeMetaData> loadAttributeMetaDataMap(final URL documentUrl) throws Exception {
-    Document document = SAX_BUILDER.build(documentUrl);
-    return parseAttributeMetaDataMap( document.getRootElement() );
-  }
-
-  /**
-   * Creates an JDOM {@link Element} for the given {@link AttributeMetaData}
-   * object.
-   * @param amd meta data for one attribute
-   */
-  public static Element createAttributeMetaDataElement(final AttributeMetaData amd) {
-    final Element element = new Element( ELEM_NAME_ATTRIBUTE , AMLURI);
-    element.setAttribute("col", String.valueOf( amd.getColIdx() ) );
-    element.setAttribute("visible", String.valueOf( amd.isVisible() ) );
-    element.setAttribute("unit", amd.getUnit() );
-    // Creating a aml:name tag...
-    element.addContent( createTranslationElement("name", amd.getTitle()) );
-    // Creating a aml:desc tag...
-    element.addContent( createTranslationElement("desc", amd.getDesc()) );
-    return element;
-  }
-
-  /**
-   * Creates an JDOM {@link Element} for the given {@link AttributeMetaData}
-   * map.
-   * @param amdMap map of attribute meta data
-   */
-  public static Element createAttributeMetaDataMapElement(final Map<Integer,AttributeMetaData> amdMap) {
-    final Element element = new Element( ELEM_NAME_AMD , AMLURI);
-    for (AttributeMetaData amd : amdMap.values())
-      element.addContent( createAttributeMetaDataElement( amd ) );
-    return element;
-  }
-
-  /**
-   * Saves a {@link AttributeMetaData AttributeMetaData-Map} to an URL.
-   * @param amdMap map of {@link AttributeMetaData}
-   * @param documentUrl {@link URL} to store the XML
-   */
-  public static void saveAttributeMetaDataMap(final Map<Integer,AttributeMetaData> amdMap, final URL documentUrl) throws Exception {
-    // Create XML-Document
-    final FileWriter out = new FileWriter( new File(documentUrl.toURI()) );
-    XML_OUTPUTTER.output(
-      createAttributeMetaDataMapElement(amdMap),
-      out
-    );
-    out.flush();
-    out.close();
-  }
-
-
-
-  /**
-   * Parses a {@link RasterLegendData} object from an JDOM-{@link Element}.
-   * This method works like {@link AMLImport#parseRasterLegendData(org.w3c.dom.Node},
-   * but for JDOM.
-   * @param element {@link Element} to parse
-   */
-  public static RasterLegendData parseRasterLegendData(Element element) {
-
-    final boolean paintGaps = Boolean.valueOf( element.getAttributeValue("paintGaps") );
-
-    RasterLegendData rld = new RasterLegendData(paintGaps);
-
-    for ( Element childElement : (List<Element>)element.getChildren() ) {
-      final String name = childElement.getName();
-      // Cancel if it's an attribute
-      if ( childElement.getChildren().size() == 0 )
-        continue;
-
-      if (name.equals( ELEM_NAME_RASTERLEGEND )) {
-        final String valueAttr = childElement.getAttributeValue("value");
-        if ( valueAttr == null )
-          throw new UnsupportedOperationException("Attribute 'value' missing for definition of <"+ELEM_NAME_RASTERLEGEND+">");
-        final double value = Double.valueOf(valueAttr);
-
-        // first and only item should be the label
-        final Element labelElement = childElement.getChild("label");
-        // id label element is missing, the translation is searched directly
-        // as childs of the rasterLegendItem element
-        Translation label = parseTranslation( labelElement != null ? labelElement : childElement );
-        rld.put(value, label);
-      }
-    }
-
-    return rld;
-  }
-
-  /**
-   * Loads a {@link RasterLegendData} object from an URL.
-   * @param documentUrl {@link URL} to parse
-   * @see #parseAttributeMetaData(Element)
-   */
-  public static RasterLegendData loadRasterLegendData(final URL documentUrl) throws Exception {
-    Document document = SAX_BUILDER.build(documentUrl);
-    return parseRasterLegendData( document.getRootElement() );
-  }
-
- /**
-   * Creates an JDOM {@link Element} for the given {@link RasterLegendData}
-   * map.
-   * @param rld raster legend data
-   */
-  public static Element createRasterLegendDataElement(final RasterLegendData rld) {
-    final Element element = new Element( ELEM_NAME_RLD , AMLURI);
-    element.setAttribute("paintGaps", rld.isPaintGaps().toString());
-    for (Double key : rld.getSortedKeys()) {
-      Element item = new Element( ELEM_NAME_RASTERLEGEND, AMLURI);
-      item.setAttribute("value", key.toString());
-      item.addContent( createTranslationElement("label", rld.get(key)) );
-      element.addContent(item);
-    }
-    return element;
-  }
-
-  /**
-   * Creates {@link RasterLegendData} from a {@link ColorMap}.
-   * @param colorMap  a color map
-   * @param paintGaps indicated whether gaps are painted between the legend items 
-   * @param digits    number of digits the grid value classes (and legend) are
-   *                  rounded to (null means no round; >= 0 means digits after comma;
-   *                  < 0 means digits before comma)    */
-  public static RasterLegendData generateRasterLegendData(ColorMap colorMap, boolean paintGaps, Integer digits) {
-    DecimalFormat    decFormat = digits != null ? new DecimalFormat( SwingUtil.getNumberFormatPattern(digits) ) : null;
-    RasterLegendData rld       = new RasterLegendData(paintGaps);
-    for (ColorMapEntry cme : colorMap.getColorMapEntries())
-    {
-      double value = StylingUtil.getQuantityFromColorMapEntry(cme);
-      String label = cme.getLabel();
-      // if no label is set (e.g. quantitative style),
-      // use the value as label
-      if ( label == null || label.equals("") )
-        if ( digits == null )
-          label = String.valueOf(value);
-        else
-          label = decFormat.format( LangUtil.round(value, digits) ); 
-      rld.put( value, new Translation("   "+label) );
-    }
-    return rld;
-  }
-
-  /**
-   * Creates {@link RasterLegendData} from the {@link ColorMap} of a style.
-   * @param style     a raster style (must contain a  {@link RasterSymbolizer})
-   * @param paintGaps indicated whether gaps are painted between the legend items 
-   * @param digits    number of digits the grid value classes (and legend) are
-   *                  rounded to (null means no round; >= 0 means digits after comma;
-   *                  < 0 means digits before comma)    */
-  public static RasterLegendData generateRasterLegendData(Style style, boolean paintGaps, Integer digits) {
-    ColorMap colorMap = StylingUtil.getColorMapFromStyle(style);
-    if ( colorMap == null)
-      throw new IllegalArgumentException("Color map can not be determined from style!");
-    return generateRasterLegendData(colorMap, paintGaps, digits);
-  }
-
-  /**
-   * Saves a {@link RasterLegendData} to an URL.
-   * @param rld raster legend data
-   * @param documentUrl {@link URL} to store the XML
-   */
-  public static void saveRasterLegendData(final RasterLegendData rld, final URL documentUrl) throws Exception {
-    // Create XML-Document
-    final FileWriter out = new FileWriter( new File(documentUrl.toURI()) );
-    XML_OUTPUTTER.output(
-      createRasterLegendDataElement(rld),
-      out
-    );
-    out.flush();
-    out.close();
-  }
-
-  /**
-   * Parses a {@link Translation} object from an JDOM-{@link Element}.
-   * This method works like {@link AMLImport#parseTranslation(org.w3c.dom.Node},
-   * but for JDOM.
-   * @param element {@link Element} to parse
-   */
-  public final static Translation parseTranslation(final Element element) {
-    Translation trans = new Translation();
-
-    if (element == null)
-     return trans;
-
-    for (final Element translationElement : (List<Element>)element.getChildren()) {
-      final String name = translationElement.getName();
-      if (name == null)
-        continue;
-
-      // lang attribute
-      String lang = translationElement.getAttributeValue("lang");
-      // set the default, if no language code is set
-      if ( lang == null )
-        lang = Translation.DEFAULT_KEY;
-
-      final String translationText = translationElement.getValue();
-      if (translationText == null)
-        trans.put(lang, "");
-      else
-        trans.put(lang, translationText);
-    }
-
-    // if no <translation> is given, the value of the node should
-    // be used as a default translation
-    if (trans.size() == 0)
-      trans.put( Translation.DEFAULT_KEY, element.getValue() );
-    //     trans = new Translation( ((List<Element>)element.getChildren()).get(0).getValue() );
-
-    return trans;
-  }
-
-  /**
-   * Creates an JDOM {@link Element} for the given {@link Translation}.
-   * @param tagname Name of the Element
-   * @param translation Translation to store in the Element
-   */
-  public final static Element createTranslationElement(String tagname, Translation translation) {
-    Element element = new Element(tagname, AMLURI);
-    if ( translation == null )
-      throw new UnsupportedOperationException("Translation element can not be created from null!");
-
-    // If only a default translation is set, the <translation lang="..">..</tranlation>
-    // part is not used
-    if (translation.keySet().size() == 1 && translation.get(Translation.DEFAULT_KEY) != null) {
-      element.addContent( translation.get(Translation.DEFAULT_KEY) );
-      return element;
-    }
-
-    // add a <translation lang="..">..</tranlation> part to the element for
-    // all languages
-    for (String lang : translation.keySet()) {
-      Element translationElement = new Element( ELEM_NAME_TRANSLATION , AMLURI);
-      translationElement.setAttribute("lang", lang);
-      String translationString = translation.get(lang);
-      if (translationString == null)
-       translationString = "";
-      translationElement.addContent( translationString );
-      element.addContent(translationElement);
-    }
-
-    return element;
-  }
-
-
-  /**
-   * Sets a style to {@link StyledLayerInterface}.
-   * @param styledObject a styled object
-   * @param style a Style
-   */
-  public static void setStyledLayerStyle(StyledLayerInterface styledObject, StyledLayerStyle<?> style) {
-    // set SLD style
-    styledObject.setStyle( style.getGeoObjectStyle() );
-    // set meta data
-    if ( styledObject        instanceof StyledGridCoverageInterface &&
-         (style.getMetaData() instanceof RasterLegendData || style.getMetaData() == null) ) {
-      RasterLegendData sourceRld = (RasterLegendData)style.getMetaData();
-      RasterLegendData destRld = ((StyledGridCoverageInterface)styledObject).getLegendMetaData();
-      if ( destRld != null && sourceRld != null ) {
-        destRld.setPaintGaps(sourceRld.isPaintGaps());
-        destRld.clear();
-        destRld.putAll( sourceRld );
-      }
-      return;
-    }
-    if ( styledObject        instanceof StyledFeatureCollectionInterface &&
-         (style.getMetaData() instanceof Map || style.getMetaData() == null) ) {
-      Map<Integer, AttributeMetaData> sourceAmd = (Map<Integer, AttributeMetaData>)style.getMetaData();
-      Map<Integer, AttributeMetaData> destAmd   = ((StyledFeatureCollectionInterface)styledObject).getAttributeMetaDataMap();
-      if ( destAmd != null && sourceAmd != null ) {
-        destAmd.clear();
-        destAmd.putAll( sourceAmd );
-      }
-      return;
-    }
-
-    throw new UnsupportedOperationException("Style is not compatible to object: " +
-                                            (style.getMetaData() == null ? null : style.getMetaData().getClass().getSimpleName()) +
-                                            " <-> " +
-                                            (styledObject == null ? null : styledObject.getClass().getSimpleName()));
-  }
-
-  /**
-   * Returns the style a {@link StyledLayerInterface} as a {@link StyledLayerStyle}.
-   * @param styledObject a styled object
-   * @return {@code StyledLayerStyle<RasterLegendData>} for {@link StyledGridCoverageInterface}
-   *         or {@code StyledLayerStyle<Map<Integer,AttributeMetaData>>} for
-   *         {@link StyledFeatureCollectionInterface}
-   */
-  public static StyledLayerStyle<?> getStyledLayerStyle(StyledLayerInterface styledObject) {
-    if ( styledObject instanceof StyledGridCoverageInterface )
-      return getStyledLayerStyle( (StyledGridCoverageInterface)styledObject );
-    if ( styledObject instanceof StyledFeatureCollectionInterface )
-      return getStyledLayerStyle( (StyledFeatureCollectionInterface)styledObject );
-    throw new UnsupportedOperationException("Unknown type of StyledLayerInterface: "+(styledObject == null ? null : styledObject.getClass().getSimpleName()));
-  }
-
-  /**
-   * Returns the style and raster meta data of a {@link StyledGridCoverageInterface}
-   * as a {@link StyledLayerStyle}.
-   * @param styledGC a styled grid coverage
-   */
-  public static StyledLayerStyle<RasterLegendData> getStyledLayerStyle(StyledGridCoverageInterface styledGC) {
-    return new StyledLayerStyle<RasterLegendData>(
-      styledGC.getStyle(),
-      styledGC.getLegendMetaData()
-    );
-  }
-
-  /**
-   * Returns the style and attribute meta data of a {@link StyledFeatureCollectionInterface}
-   * as a {@link StyledLayerStyle}.
-   * @param styledFC a styled feature collection
-   */
-  public static StyledLayerStyle<Map<Integer,AttributeMetaData>> getStyledLayerStyle(StyledFeatureCollectionInterface styledFC) {
-    return new StyledLayerStyle<Map<Integer,AttributeMetaData>>(
-      styledFC.getStyle(),
-      styledFC.getAttributeMetaDataMap()
-    );
-  }
-
-  /**
-   * Loads a {@linkplain Style SLD-Style} and {@linkplain RasterLegendData Raster-LegendData}
-   * for a given geo-object (raster) source. The SLD file must be present. A missing
-   * raster legend-data file is tolerated.
-   * @param geoObjectURL URL of the (already read) raster object
-   * @param sldExt file extention for the SLD file
-   * @param rldExt file extention for the raster legend-data file
-   * @return {@code null} in case of any error
-   */
-  public static StyledLayerStyle<RasterLegendData> loadStyledRasterStyle(URL geoObjectURL, String sldExt, String rldExt) {
-    RasterLegendData metaData = null;
-    Style sldStyle = null;
-    try {
-      Style[] styles = StylingUtil.loadSLD(IOUtil.changeUrlExt(geoObjectURL, sldExt));
-      // SLD must be present
-      if ( styles == null || styles.length == 0 )
-        return null;
-      sldStyle = styles[0];
-    }
-    catch (Exception err) {
-      // SLD must be present
-      LangUtil.logDebugError(LOGGER,err);
-      return null;
-    }
-
-    try {
-      metaData = StyledLayerUtil.loadRasterLegendData( IOUtil.changeUrlExt(geoObjectURL,rldExt) );
-    } catch (FileNotFoundException err) {
-      // ignore missing raster legend data
-    } catch (Exception err) {
-      // any other error during legend data creation leads to error
-      LangUtil.logDebugError(LOGGER,err);
-      return null;
-    }
-    return new StyledLayerStyle<RasterLegendData>(sldStyle, metaData);
-  }
-
-  /**
-   * Loads a {@linkplain Style SLD-Style} from a {@code .sld} file and
-   * {@linkplain RasterLegendData Raster-LegendData} from a {@code .rld} file
-   * for a given geo-object (raster) source. The SLD file must be present. A missing
-   * raster legend-data file is tolerated.
-   * @param geoObjectURL URL of the (already read) raster object
-   * @param sldExt file extention for the SLD file
-   * @param rldExt file extention for the raster legend-data file
-   * @return {@code null} in case of any error
-   */
-  public static StyledLayerStyle<RasterLegendData> loadStyledRasterStyle(URL geoObjectURL) {
-    return loadStyledRasterStyle(geoObjectURL, "sld", "rld");
-  }
-
-  /**
-   * Loads a {@linkplain Style SLD-Style} and a {@linkplain AttributeMetaData AttributeMetaData-Map}
-   * for a given geo-object (feature) source. The SLD file must be present. A missing
-   * attribute meta-data file is tolerated.
-   * @param geoObjectURL URL of the (already read) feature object
-   * @param sldExt file extention for the SLD file
-   * @param rldExt file extention for the raster legend-data file
-   * @return {@code null} in case of any error
-   */
-  public static StyledLayerStyle<Map<Integer,AttributeMetaData>> loadStyledFeatureStyle(URL geoObjectURL, String sldExt, String rldExt) {
-    Map<Integer,AttributeMetaData> metaData = null;
-    Style                          sldStyle = null;
-    try {
-      Style[] styles = StylingUtil.loadSLD(IOUtil.changeUrlExt(geoObjectURL, sldExt));
-      // SLD must be present
-      if ( styles == null || styles.length == 0 )
-        return null;
-      sldStyle = styles[0];
-    } catch (Exception err) {
-      // SLD must be present
-      LangUtil.logDebugError(LOGGER,err);
-      return null;
-    }
-
-    try {
-      metaData = StyledLayerUtil.loadAttributeMetaDataMap( IOUtil.changeUrlExt(geoObjectURL,rldExt) );
-    } catch (FileNotFoundException err) {
-      // ignore missing attribute meta data
-    } catch (Exception err) {
-      // any other error during meta data creation leads to error
-      LangUtil.logDebugError(LOGGER,err);
-      return null;
-    }
-
-    return new StyledLayerStyle<Map<Integer,AttributeMetaData>>(sldStyle, metaData);
-  }
-
-  /**
-   * Loads a {@linkplain Style SLD-Style} from a {@code .sld} file and
-   * {@linkplain AttributeMetaData AttributeMetaData-Map} from a {@code .amd} file
-   * for a given geo-object (feature) source. The SLD file must be present. A missing
-   * attribute meta-data file is tolerated.
-   * @param geoObjectURL URL of the (already read) feature object
-   * @param sldExt file extention for the SLD file
-   * @param rldExt file extention for the raster legend-data file
-   * @return {@code null} in case of any error
-   */
-  public static StyledLayerStyle<Map<Integer,AttributeMetaData>> loadStyledFeatureStyle(URL geoObjectURL) {
-    return loadStyledFeatureStyle(geoObjectURL, "sld", "amd");
-  }
-
-  /**
-   * Stores a {@linkplain Style SLD-Style} and {@linkplain RasterLegendData Raster-LegendData}
-   * for a given geo-object (raster) source.
-   * @param style  style to save
-   * @param geoObjectURL URL of the raster object
-   * @param sldExt file extention for the SLD file
-   * @param mdExt file extention for the meta-data file
-   */
-  public static <T> void saveStyledLayerStyle(StyledLayerStyle<T> style, URL geoObjectURL, String sldExt, String mdExt) throws Exception {
-    // Store the SLD
-    Style sldStyle = style.getGeoObjectStyle();
-    if ( sldStyle != null ) {
-      StylingUtil.saveStyleToSLD(
-         sldStyle,
-         IOUtil.changeFileExt(
-              new File(geoObjectURL.toURI()),
-              sldExt
-         )
-      );
-    }
-
-    // Store the meta data
-    T metaData = style.getMetaData();
-    if ( metaData != null ) {
-      if ( metaData instanceof RasterLegendData ) {
-        saveRasterLegendData(
-            (RasterLegendData)metaData,
-            IOUtil.changeUrlExt(geoObjectURL,mdExt)
-        );
-//      } else if ( metaData instanceof Map<Integer,AttributeMetaData> ) { // LEIDER NICHT KOMPILIERBAR!!
-      } else if ( metaData instanceof Map ) {
-        saveAttributeMetaDataMap(
-            (Map<Integer,AttributeMetaData>)metaData,
-            IOUtil.changeUrlExt(geoObjectURL,mdExt)
-        );
-      } else
-        throw new UnsupportedOperationException("Export for meta data not yet supported: "+metaData.getClass().getSimpleName());
-    }
-  }
-
-  /**
-   * Stores the {@linkplain Style SLD-Style} to a {@code .sld} file and
-   * the meta data ({@link RasterLegendData} or {@link AttributeMetaData})
-   * to a {@code .rld} or {@code .amd} file.
-   * for a given geo-object source.
-   * @param style  style to save
-   * @param geoObjectURL URL of the (already read) raster object
-   */
-  public static void saveStyledLayerStyle(StyledLayerStyle<?> style, URL geoObjectURL) throws Exception {
-    if ( style.getMetaData() instanceof RasterLegendData )
-      saveStyledLayerStyle(style,geoObjectURL, "sld", "rld");
-    else
-      saveStyledLayerStyle(style,geoObjectURL, "sld", "amd");
-  }
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package skrueger.geotools;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.net.URL;
+import java.text.DecimalFormat;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.apache.log4j.Logger;
+import org.geotools.coverage.grid.GridCoverage2D;
+import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader;
+import org.geotools.feature.FeatureCollection;
+import org.geotools.map.DefaultMapLayer;
+import org.geotools.map.MapLayer;
+import org.geotools.styling.ColorMap;
+import org.geotools.styling.ColorMapEntry;
+import org.geotools.styling.RasterSymbolizer;
+import org.geotools.styling.Style;
+import org.jdom.Document;
+import org.jdom.Element;
+import org.jdom.input.SAXBuilder;
+import org.jdom.output.XMLOutputter;
+
+import schmitzm.geotools.styling.StylingUtil;
+import schmitzm.io.IOUtil;
+import schmitzm.lang.LangUtil;
+import schmitzm.swing.SwingUtil;
+import skrueger.AttributeMetaData;
+import skrueger.RasterLegendData;
+import skrueger.i8n.Translation;
+
+/**
+ * This class provides static helper methods for dealing with
+ * {@link StyledLayerInterface} stuff.
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+ * @version 1.0
+ */
+public class StyledLayerUtil {
+  private static final Logger LOGGER = Logger.getLogger(StyledLayerUtil.class.getName());
+  private static final SAXBuilder SAX_BUILDER = new SAXBuilder();
+  private static final XMLOutputter XML_OUTPUTTER = new XMLOutputter();
+
+  /** URL for Atlas XML schema */
+  public static final String AMLURI = "http://www.wikisquare.de/AtlasML";
+  /** Name of the XML Element for the attribute meta data map */
+  public static final String ELEM_NAME_AMD = "attributeMetaData";
+  /** Name of the XML Element for the raster legend data */
+  public static final String ELEM_NAME_RLD = "rasterLegendData";
+  /** Name of the XML Element for an attribute meta data map entry */
+  public static final String ELEM_NAME_ATTRIBUTE = "dataAttribute";
+  /** Name of the XML Element for an raster legend data entry */
+  public static final String ELEM_NAME_RASTERLEGEND = "rasterLegendItem";
+  /** Name of the XML Element for a translation */
+  public static final String ELEM_NAME_TRANSLATION = "translation";
+
+  /**
+   * Creates a Geotools {@link MapLayer} from an object. If the object is a
+   * {@link StyledLayerInterface} then its sytle is used. In case of direct
+   * Geotools objects ({@link GridCoverage2D}, {@link AbstractGridCoverage2DReader},
+   * {@link FeatureCollection}) a default style is generated.
+   * @param object an Object
+   * @exception Exception if {@code null} is given as object or an error occurs during layer creation
+   */
+  public static MapLayer createMapLayer(Object object) throws Exception {
+    return createMapLayer(object,null);
+  }
+
+  /**
+   * Creates a Geotools {@link MapLayer} from an object. If the object is a
+   * {@link StyledLayerInterface} then its sytle is used. In case of direct
+   * Geotools objects ({@link GridCoverage2D}, {@link AbstractGridCoverage2DReader},
+   * {@link FeatureCollection}) a default style is generated.
+   * @param object an Object
+   * @param forcedStyle (SLD-)Style to force for the object
+   * @exception Exception if {@code null} is given as object or an error occurs during layer creation
+   */
+  public static MapLayer createMapLayer(Object object, Style forcedStyle) throws Exception {
+    MapLayer layer     = null;
+    Style    style     = null;
+    if ( object instanceof StyledLayerInterface ) {
+      style =  ((StyledLayerInterface<?>)object).getStyle();
+      object = ((StyledLayerInterface<?>)object).getGeoObject();
+    }
+    if ( forcedStyle != null )
+      style = forcedStyle;
+    if ( style == null )
+      style = StylingUtil.createDefaultStyle(object);
+
+    if (object instanceof GridCoverage2D)
+      layer = new DefaultMapLayer( (GridCoverage2D) object, style);
+    if (object instanceof AbstractGridCoverage2DReader)
+      layer = new DefaultMapLayer( (AbstractGridCoverage2DReader) object, style);
+    if (object instanceof FeatureCollection)
+      layer = new DefaultMapLayer( (FeatureCollection) object, style);
+
+    if ( layer == null )
+      throw new Exception("Can not create MapLayer from "+(object == null ? "null" : object.getClass()));
+
+    return layer;
+  }
+
+  /**
+   * Creates an default instance of {@link StyledLayerInterface} for a Geotools
+   * object ({@link GridCoverage2D}, {@link FeatureCollection}) with a default
+   * style.
+   * @param object an Object
+   * @param title  title for the object
+   * @exception UnsupportedOperationException if {@code null} is given as object or an error occurs during creation
+   */
+  public static StyledLayerInterface<?> createStyledLayer(Object object, String title) {
+     return createStyledLayer(object, title, null);
+  }
+
+  /**
+   * Creates an default instance of {@link StyledLayerInterface} for a Geotools
+   * object ({@link GridCoverage2D}, {@link FeatureCollection}) with a given
+   * style.
+   * @param object an Object
+   * @param title  title for the object
+   * @param style  style and meta data for the object
+   * @exception UnsupportedOperationException if {@code null} is given as object or an error occurs during creation
+   */
+  public static StyledLayerInterface<?> createStyledLayer(Object object, String title, StyledLayerStyle style) {
+    StyledLayerInterface<?> styledLayer = null;
+
+    String id = (title != null) ? title : "defaultID";
+
+    if ( object instanceof GridCoverage2D )
+      styledLayer = new StyledGridCoverage(
+          (GridCoverage2D)object,
+          id,
+          title,
+          style
+      );
+    else if ( object instanceof AbstractGridCoverage2DReader )
+           styledLayer = new StyledGridCoverageReader(
+               (AbstractGridCoverage2DReader)object,
+               id,
+               title,
+               style
+           );
+    else if ( object instanceof FeatureCollection )
+      styledLayer = new StyledFeatureCollection(
+          (FeatureCollection)object,
+          id,
+          title,
+          style
+      );
+    
+    if ( styledLayer == null )
+      throw new UnsupportedOperationException("Can not create StyledLayerInterface object from "+(object == null ? "null" : object.getClass()));
+
+    return styledLayer;
+  }
+
+  /**
+   * Return only the visible or invisible entries of an AttributeMetaData-Map.
+   * @param amdMap AttributeMetaData-Map
+   * @param visible indicated whether the visible or invisible entries are
+   *                returned 
+   */
+  public static SortedMap<Integer,AttributeMetaData> getVisibleAttributeMetaData(Map<Integer,AttributeMetaData> amdMap, boolean visible) {
+    SortedMap<Integer,AttributeMetaData> filteredMap = new TreeMap<Integer,AttributeMetaData>();
+    for (AttributeMetaData amd : amdMap.values())
+      if ( amd.isVisible() )
+        filteredMap.put(amd.getColIdx(), amd);
+    
+    return filteredMap;
+  }
+  
+  
+  /**
+   * Parses a {@link AttributeMetaData} object from an JDOM-{@link Element}.
+   * This method works like {@link AMLImport#parseDataAttribute(org.w3c.dom.Node},
+   * but for JDOM.
+   * @param element {@link Element} to parse
+   */
+  public static AttributeMetaData parseAttributeMetaData(final Element element) {
+    final Integer col = Integer.valueOf(element.getAttributeValue("col"));
+    final Boolean visible = Boolean.valueOf(element.getAttributeValue("visible"));
+    final String unit = element.getAttributeValue("unit");
+
+    Translation name = new Translation();
+    Translation desc = new Translation();
+    for (final Element childElement : (List<Element>)element.getChildren()) {
+      if (childElement.getName() == null)
+        continue;
+
+      if (childElement.getName().equals("name"))
+        name = parseTranslation(childElement);
+      else if (childElement.getName().equals("desc"))
+        desc = parseTranslation(childElement);
+    }
+    return new AttributeMetaData(col, visible, name, desc, unit);
+  }
+
+  /**
+   * Parses a {@link AttributeMetaData} map from an JDOM-{@link Element}
+   * with {@code <attribute>}-childs.
+   * @param element {@link Element} to parse
+   */
+  public static Map<Integer,AttributeMetaData> parseAttributeMetaDataMap(final Element element) {
+    HashMap<Integer,AttributeMetaData> metaData = new HashMap<Integer,AttributeMetaData>();
+    List<Element> attributesElements = element.getChildren( ELEM_NAME_ATTRIBUTE );
+    for (Element attibuteElement : attributesElements)
+    {
+      AttributeMetaData attrMetaData = parseAttributeMetaData( attibuteElement );
+      metaData.put( attrMetaData.getColIdx(), attrMetaData );
+    }
+    return metaData;
+  }
+
+  /**
+   * Loads a {@link AttributeMetaData} object from an URL.
+   * @param documentUrl {@link URL} to parse
+   * @see #parseAttributeMetaData(Element)
+   */
+  public static Map<Integer,AttributeMetaData> loadAttributeMetaDataMap(final URL documentUrl) throws Exception {
+    Document document = SAX_BUILDER.build(documentUrl);
+    return parseAttributeMetaDataMap( document.getRootElement() );
+  }
+
+  /**
+   * Creates an JDOM {@link Element} for the given {@link AttributeMetaData}
+   * object.
+   * @param amd meta data for one attribute
+   */
+  public static Element createAttributeMetaDataElement(final AttributeMetaData amd) {
+    final Element element = new Element( ELEM_NAME_ATTRIBUTE , AMLURI);
+    element.setAttribute("col", String.valueOf( amd.getColIdx() ) );
+    element.setAttribute("visible", String.valueOf( amd.isVisible() ) );
+    element.setAttribute("unit", amd.getUnit() );
+    // Creating a aml:name tag...
+    element.addContent( createTranslationElement("name", amd.getTitle()) );
+    // Creating a aml:desc tag...
+    element.addContent( createTranslationElement("desc", amd.getDesc()) );
+    return element;
+  }
+
+  /**
+   * Creates an JDOM {@link Element} for the given {@link AttributeMetaData}
+   * map.
+   * @param amdMap map of attribute meta data
+   */
+  public static Element createAttributeMetaDataMapElement(final Map<Integer,AttributeMetaData> amdMap) {
+    final Element element = new Element( ELEM_NAME_AMD , AMLURI);
+    for (AttributeMetaData amd : amdMap.values())
+      element.addContent( createAttributeMetaDataElement( amd ) );
+    return element;
+  }
+
+  /**
+   * Saves a {@link AttributeMetaData AttributeMetaData-Map} to an URL.
+   * @param amdMap map of {@link AttributeMetaData}
+   * @param documentUrl {@link URL} to store the XML
+   */
+  public static void saveAttributeMetaDataMap(final Map<Integer,AttributeMetaData> amdMap, final URL documentUrl) throws Exception {
+    // Create XML-Document
+    final FileWriter out = new FileWriter( new File(documentUrl.toURI()) );
+    XML_OUTPUTTER.output(
+      createAttributeMetaDataMapElement(amdMap),
+      out
+    );
+    out.flush();
+    out.close();
+  }
+
+
+
+  /**
+   * Parses a {@link RasterLegendData} object from an JDOM-{@link Element}.
+   * This method works like {@link AMLImport#parseRasterLegendData(org.w3c.dom.Node},
+   * but for JDOM.
+   * @param element {@link Element} to parse
+   */
+  public static RasterLegendData parseRasterLegendData(Element element) {
+
+    final boolean paintGaps = Boolean.valueOf( element.getAttributeValue("paintGaps") );
+
+    RasterLegendData rld = new RasterLegendData(paintGaps);
+
+    for ( Element childElement : (List<Element>)element.getChildren() ) {
+      final String name = childElement.getName();
+      // Cancel if it's an attribute
+      if ( childElement.getChildren().size() == 0 )
+        continue;
+
+      if (name.equals( ELEM_NAME_RASTERLEGEND )) {
+        final String valueAttr = childElement.getAttributeValue("value");
+        if ( valueAttr == null )
+          throw new UnsupportedOperationException("Attribute 'value' missing for definition of <"+ELEM_NAME_RASTERLEGEND+">");
+        final double value = Double.valueOf(valueAttr);
+
+        // first and only item should be the label
+        final Element labelElement = childElement.getChild("label");
+        // id label element is missing, the translation is searched directly
+        // as childs of the rasterLegendItem element
+        Translation label = parseTranslation( labelElement != null ? labelElement : childElement );
+        rld.put(value, label);
+      }
+    }
+
+    return rld;
+  }
+
+  /**
+   * Loads a {@link RasterLegendData} object from an URL.
+   * @param documentUrl {@link URL} to parse
+   * @see #parseAttributeMetaData(Element)
+   */
+  public static RasterLegendData loadRasterLegendData(final URL documentUrl) throws Exception {
+    Document document = SAX_BUILDER.build(documentUrl);
+    return parseRasterLegendData( document.getRootElement() );
+  }
+
+ /**
+   * Creates an JDOM {@link Element} for the given {@link RasterLegendData}
+   * map.
+   * @param rld raster legend data
+   */
+  public static Element createRasterLegendDataElement(final RasterLegendData rld) {
+    final Element element = new Element( ELEM_NAME_RLD , AMLURI);
+    element.setAttribute("paintGaps", rld.isPaintGaps().toString());
+    for (Double key : rld.getSortedKeys()) {
+      Element item = new Element( ELEM_NAME_RASTERLEGEND, AMLURI);
+      item.setAttribute("value", key.toString());
+      item.addContent( createTranslationElement("label", rld.get(key)) );
+      element.addContent(item);
+    }
+    return element;
+  }
+
+  /**
+   * Creates {@link RasterLegendData} from a {@link ColorMap}.
+   * @param colorMap  a color map
+   * @param paintGaps indicated whether gaps are painted between the legend items 
+   * @param digits    number of digits the grid value classes (and legend) are
+   *                  rounded to (null means no round; >= 0 means digits after comma;
+   *                  < 0 means digits before comma)    */
+  public static RasterLegendData generateRasterLegendData(ColorMap colorMap, boolean paintGaps, Integer digits) {
+    DecimalFormat    decFormat = digits != null ? new DecimalFormat( SwingUtil.getNumberFormatPattern(digits) ) : null;
+    RasterLegendData rld       = new RasterLegendData(paintGaps);
+    for (ColorMapEntry cme : colorMap.getColorMapEntries())
+    {
+      double value = StylingUtil.getQuantityFromColorMapEntry(cme);
+      String label = cme.getLabel();
+      // if no label is set (e.g. quantitative style),
+      // use the value as label
+      if ( label == null || label.equals("") )
+        if ( digits == null )
+          label = String.valueOf(value);
+        else
+          label = decFormat.format( LangUtil.round(value, digits) ); 
+      rld.put( value, new Translation("   "+label) );
+    }
+    return rld;
+  }
+
+  /**
+   * Creates {@link RasterLegendData} from the {@link ColorMap} of a style.
+   * @param style     a raster style (must contain a  {@link RasterSymbolizer})
+   * @param paintGaps indicated whether gaps are painted between the legend items 
+   * @param digits    number of digits the grid value classes (and legend) are
+   *                  rounded to (null means no round; >= 0 means digits after comma;
+   *                  < 0 means digits before comma)    */
+  public static RasterLegendData generateRasterLegendData(Style style, boolean paintGaps, Integer digits) {
+    ColorMap colorMap = StylingUtil.getColorMapFromStyle(style);
+    if ( colorMap == null)
+      throw new IllegalArgumentException("Color map can not be determined from style!");
+    return generateRasterLegendData(colorMap, paintGaps, digits);
+  }
+
+  /**
+   * Saves a {@link RasterLegendData} to an URL.
+   * @param rld raster legend data
+   * @param documentUrl {@link URL} to store the XML
+   */
+  public static void saveRasterLegendData(final RasterLegendData rld, final URL documentUrl) throws Exception {
+    // Create XML-Document
+    final FileWriter out = new FileWriter( new File(documentUrl.toURI()) );
+    XML_OUTPUTTER.output(
+      createRasterLegendDataElement(rld),
+      out
+    );
+    out.flush();
+    out.close();
+  }
+
+  /**
+   * Parses a {@link Translation} object from an JDOM-{@link Element}.
+   * This method works like {@link AMLImport#parseTranslation(org.w3c.dom.Node},
+   * but for JDOM.
+   * @param element {@link Element} to parse
+   */
+  public final static Translation parseTranslation(final Element element) {
+    Translation trans = new Translation();
+
+    if (element == null)
+     return trans;
+
+    for (final Element translationElement : (List<Element>)element.getChildren()) {
+      final String name = translationElement.getName();
+      if (name == null)
+        continue;
+
+      // lang attribute
+      String lang = translationElement.getAttributeValue("lang");
+      // set the default, if no language code is set
+      if ( lang == null )
+        lang = Translation.DEFAULT_KEY;
+
+      final String translationText = translationElement.getValue();
+      if (translationText == null)
+        trans.put(lang, "");
+      else
+        trans.put(lang, translationText);
+    }
+
+    // if no <translation> is given, the value of the node should
+    // be used as a default translation
+    if (trans.size() == 0)
+      trans.put( Translation.DEFAULT_KEY, element.getValue() );
+    //     trans = new Translation( ((List<Element>)element.getChildren()).get(0).getValue() );
+
+    return trans;
+  }
+
+  /**
+   * Creates an JDOM {@link Element} for the given {@link Translation}.
+   * @param tagname Name of the Element
+   * @param translation Translation to store in the Element
+   */
+  public final static Element createTranslationElement(String tagname, Translation translation) {
+    Element element = new Element(tagname, AMLURI);
+    if ( translation == null )
+      throw new UnsupportedOperationException("Translation element can not be created from null!");
+
+    // If only a default translation is set, the <translation lang="..">..</tranlation>
+    // part is not used
+    if (translation.keySet().size() == 1 && translation.get(Translation.DEFAULT_KEY) != null) {
+      element.addContent( translation.get(Translation.DEFAULT_KEY) );
+      return element;
+    }
+
+    // add a <translation lang="..">..</tranlation> part to the element for
+    // all languages
+    for (String lang : translation.keySet()) {
+      Element translationElement = new Element( ELEM_NAME_TRANSLATION , AMLURI);
+      translationElement.setAttribute("lang", lang);
+      String translationString = translation.get(lang);
+      if (translationString == null)
+       translationString = "";
+      translationElement.addContent( translationString );
+      element.addContent(translationElement);
+    }
+
+    return element;
+  }
+
+
+  /**
+   * Sets a style to {@link StyledLayerInterface}.
+   * @param styledObject a styled object
+   * @param style a Style
+   */
+  public static void setStyledLayerStyle(StyledLayerInterface styledObject, StyledLayerStyle<?> style) {
+    // set SLD style
+    styledObject.setStyle( style.getGeoObjectStyle() );
+    // set meta data
+    if ( styledObject        instanceof StyledGridCoverageInterface &&
+         (style.getMetaData() instanceof RasterLegendData || style.getMetaData() == null) ) {
+      RasterLegendData sourceRld = (RasterLegendData)style.getMetaData();
+      RasterLegendData destRld = ((StyledGridCoverageInterface)styledObject).getLegendMetaData();
+      if ( destRld != null && sourceRld != null ) {
+        destRld.setPaintGaps(sourceRld.isPaintGaps());
+        destRld.clear();
+        destRld.putAll( sourceRld );
+      }
+      return;
+    }
+    if ( styledObject        instanceof StyledFeatureCollectionInterface &&
+         (style.getMetaData() instanceof Map || style.getMetaData() == null) ) {
+      Map<Integer, AttributeMetaData> sourceAmd = (Map<Integer, AttributeMetaData>)style.getMetaData();
+      Map<Integer, AttributeMetaData> destAmd   = ((StyledFeatureCollectionInterface)styledObject).getAttributeMetaDataMap();
+      if ( destAmd != null && sourceAmd != null ) {
+        destAmd.clear();
+        destAmd.putAll( sourceAmd );
+      }
+      return;
+    }
+
+    throw new UnsupportedOperationException("Style is not compatible to object: " +
+                                            (style.getMetaData() == null ? null : style.getMetaData().getClass().getSimpleName()) +
+                                            " <-> " +
+                                            (styledObject == null ? null : styledObject.getClass().getSimpleName()));
+  }
+
+  /**
+   * Returns the style a {@link StyledLayerInterface} as a {@link StyledLayerStyle}.
+   * @param styledObject a styled object
+   * @return {@code StyledLayerStyle<RasterLegendData>} for {@link StyledGridCoverageInterface}
+   *         or {@code StyledLayerStyle<Map<Integer,AttributeMetaData>>} for
+   *         {@link StyledFeatureCollectionInterface}
+   */
+  public static StyledLayerStyle<?> getStyledLayerStyle(StyledLayerInterface styledObject) {
+    if ( styledObject instanceof StyledGridCoverageInterface )
+      return getStyledLayerStyle( (StyledGridCoverageInterface)styledObject );
+    if ( styledObject instanceof StyledFeatureCollectionInterface )
+      return getStyledLayerStyle( (StyledFeatureCollectionInterface)styledObject );
+    throw new UnsupportedOperationException("Unknown type of StyledLayerInterface: "+(styledObject == null ? null : styledObject.getClass().getSimpleName()));
+  }
+
+  /**
+   * Returns the style and raster meta data of a {@link StyledGridCoverageInterface}
+   * as a {@link StyledLayerStyle}.
+   * @param styledGC a styled grid coverage
+   */
+  public static StyledLayerStyle<RasterLegendData> getStyledLayerStyle(StyledGridCoverageInterface styledGC) {
+    return new StyledLayerStyle<RasterLegendData>(
+      styledGC.getStyle(),
+      styledGC.getLegendMetaData()
+    );
+  }
+
+  /**
+   * Returns the style and attribute meta data of a {@link StyledFeatureCollectionInterface}
+   * as a {@link StyledLayerStyle}.
+   * @param styledFC a styled feature collection
+   */
+  public static StyledLayerStyle<Map<Integer,AttributeMetaData>> getStyledLayerStyle(StyledFeatureCollectionInterface styledFC) {
+    return new StyledLayerStyle<Map<Integer,AttributeMetaData>>(
+      styledFC.getStyle(),
+      styledFC.getAttributeMetaDataMap()
+    );
+  }
+
+  /**
+   * Loads a {@linkplain Style SLD-Style} and {@linkplain RasterLegendData Raster-LegendData}
+   * for a given geo-object (raster) source. The SLD file must be present. A missing
+   * raster legend-data file is tolerated.
+   * @param geoObjectURL URL of the (already read) raster object
+   * @param sldExt file extention for the SLD file
+   * @param rldExt file extention for the raster legend-data file
+   * @return {@code null} in case of any error
+   */
+  public static StyledLayerStyle<RasterLegendData> loadStyledRasterStyle(URL geoObjectURL, String sldExt, String rldExt) {
+    RasterLegendData metaData = null;
+    Style sldStyle = null;
+    try {
+      Style[] styles = StylingUtil.loadSLD(IOUtil.changeUrlExt(geoObjectURL, sldExt));
+      // SLD must be present
+      if ( styles == null || styles.length == 0 )
+        return null;
+      sldStyle = styles[0];
+    }
+    catch (Exception err) {
+      // SLD must be present
+      LangUtil.logDebugError(LOGGER,err);
+      return null;
+    }
+
+    try {
+      metaData = StyledLayerUtil.loadRasterLegendData( IOUtil.changeUrlExt(geoObjectURL,rldExt) );
+    } catch (FileNotFoundException err) {
+      // ignore missing raster legend data
+    } catch (Exception err) {
+      // any other error during legend data creation leads to error
+      LangUtil.logDebugError(LOGGER,err);
+      return null;
+    }
+    return new StyledLayerStyle<RasterLegendData>(sldStyle, metaData);
+  }
+
+  /**
+   * Loads a {@linkplain Style SLD-Style} from a {@code .sld} file and
+   * {@linkplain RasterLegendData Raster-LegendData} from a {@code .rld} file
+   * for a given geo-object (raster) source. The SLD file must be present. A missing
+   * raster legend-data file is tolerated.
+   * @param geoObjectURL URL of the (already read) raster object
+   * @param sldExt file extention for the SLD file
+   * @param rldExt file extention for the raster legend-data file
+   * @return {@code null} in case of any error
+   */
+  public static StyledLayerStyle<RasterLegendData> loadStyledRasterStyle(URL geoObjectURL) {
+    return loadStyledRasterStyle(geoObjectURL, "sld", "rld");
+  }
+
+  /**
+   * Loads a {@linkplain Style SLD-Style} and a {@linkplain AttributeMetaData AttributeMetaData-Map}
+   * for a given geo-object (feature) source. The SLD file must be present. A missing
+   * attribute meta-data file is tolerated.
+   * @param geoObjectURL URL of the (already read) feature object
+   * @param sldExt file extention for the SLD file
+   * @param rldExt file extention for the raster legend-data file
+   * @return {@code null} in case of any error
+   */
+  public static StyledLayerStyle<Map<Integer,AttributeMetaData>> loadStyledFeatureStyle(URL geoObjectURL, String sldExt, String rldExt) {
+    Map<Integer,AttributeMetaData> metaData = null;
+    Style                          sldStyle = null;
+    try {
+      Style[] styles = StylingUtil.loadSLD(IOUtil.changeUrlExt(geoObjectURL, sldExt));
+      // SLD must be present
+      if ( styles == null || styles.length == 0 )
+        return null;
+      sldStyle = styles[0];
+    } catch (Exception err) {
+      // SLD must be present
+      LangUtil.logDebugError(LOGGER,err);
+      return null;
+    }
+
+    try {
+      metaData = StyledLayerUtil.loadAttributeMetaDataMap( IOUtil.changeUrlExt(geoObjectURL,rldExt) );
+    } catch (FileNotFoundException err) {
+      // ignore missing attribute meta data
+    } catch (Exception err) {
+      // any other error during meta data creation leads to error
+      LangUtil.logDebugError(LOGGER,err);
+      return null;
+    }
+
+    return new StyledLayerStyle<Map<Integer,AttributeMetaData>>(sldStyle, metaData);
+  }
+
+  /**
+   * Loads a {@linkplain Style SLD-Style} from a {@code .sld} file and
+   * {@linkplain AttributeMetaData AttributeMetaData-Map} from a {@code .amd} file
+   * for a given geo-object (feature) source. The SLD file must be present. A missing
+   * attribute meta-data file is tolerated.
+   * @param geoObjectURL URL of the (already read) feature object
+   * @param sldExt file extention for the SLD file
+   * @param rldExt file extention for the raster legend-data file
+   * @return {@code null} in case of any error
+   */
+  public static StyledLayerStyle<Map<Integer,AttributeMetaData>> loadStyledFeatureStyle(URL geoObjectURL) {
+    return loadStyledFeatureStyle(geoObjectURL, "sld", "amd");
+  }
+
+  /**
+   * Stores a {@linkplain Style SLD-Style} and {@linkplain RasterLegendData Raster-LegendData}
+   * for a given geo-object (raster) source.
+   * @param style  style to save
+   * @param geoObjectURL URL of the raster object
+   * @param sldExt file extention for the SLD file
+   * @param mdExt file extention for the meta-data file
+   */
+  public static <T> void saveStyledLayerStyle(StyledLayerStyle<T> style, URL geoObjectURL, String sldExt, String mdExt) throws Exception {
+    // Store the SLD
+    Style sldStyle = style.getGeoObjectStyle();
+    if ( sldStyle != null ) {
+      StylingUtil.saveStyleToSLD(
+         sldStyle,
+         IOUtil.changeFileExt(
+              new File(geoObjectURL.toURI()),
+              sldExt
+         )
+      );
+    }
+
+    // Store the meta data
+    T metaData = style.getMetaData();
+    if ( metaData != null ) {
+      if ( metaData instanceof RasterLegendData ) {
+        saveRasterLegendData(
+            (RasterLegendData)metaData,
+            IOUtil.changeUrlExt(geoObjectURL,mdExt)
+        );
+//      } else if ( metaData instanceof Map<Integer,AttributeMetaData> ) { // LEIDER NICHT KOMPILIERBAR!!
+      } else if ( metaData instanceof Map ) {
+        saveAttributeMetaDataMap(
+            (Map<Integer,AttributeMetaData>)metaData,
+            IOUtil.changeUrlExt(geoObjectURL,mdExt)
+        );
+      } else
+        throw new UnsupportedOperationException("Export for meta data not yet supported: "+metaData.getClass().getSimpleName());
+    }
+  }
+
+  /**
+   * Stores the {@linkplain Style SLD-Style} to a {@code .sld} file and
+   * the meta data ({@link RasterLegendData} or {@link AttributeMetaData})
+   * to a {@code .rld} or {@code .amd} file.
+   * for a given geo-object source.
+   * @param style  style to save
+   * @param geoObjectURL URL of the (already read) raster object
+   */
+  public static void saveStyledLayerStyle(StyledLayerStyle<?> style, URL geoObjectURL) throws Exception {
+    if ( style.getMetaData() instanceof RasterLegendData )
+      saveStyledLayerStyle(style,geoObjectURL, "sld", "rld");
+    else
+      saveStyledLayerStyle(style,geoObjectURL, "sld", "amd");
+  }
+
+}

Modified: trunk/src/skrueger/geotools/StyledRasterInterface.java
===================================================================
--- trunk/src/skrueger/geotools/StyledRasterInterface.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/StyledRasterInterface.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,19 +1,48 @@
-package skrueger.geotools;
-
-import skrueger.RasterLegendData;
-
-/**
- * A {@link StyledLayerInterface} that is associated to a {@link RasterLegendData}. The datatype is not yet defined.
- * 
- * @see StyledGridCoverageInterface
- * 
- * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
- */
-public interface StyledRasterInterface<E> extends StyledLayerInterface<E> {
-
-	/**
-	 * @return A {@link RasterLegendData} object with pairs of value / label information
-	 */
-	RasterLegendData getLegendMetaData();
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package skrueger.geotools;
+
+import skrueger.RasterLegendData;
+
+/**
+ * A {@link StyledLayerInterface} that is associated to a {@link RasterLegendData}. The datatype is not yet defined.
+ * 
+ * @see StyledGridCoverageInterface
+ * 
+ * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
+ */
+public interface StyledRasterInterface<E> extends StyledLayerInterface<E> {
+
+	/**
+	 * @return A {@link RasterLegendData} object with pairs of value / label information
+	 */
+	RasterLegendData getLegendMetaData();
+
+}

Modified: trunk/src/skrueger/geotools/ZoomRestrictableGridInterface.java
===================================================================
--- trunk/src/skrueger/geotools/ZoomRestrictableGridInterface.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/ZoomRestrictableGridInterface.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,27 +1,56 @@
-package skrueger.geotools;
-
-/**
- * Classes that implement {@link ZoomRestrictableGridInterface} can be restricted to their max- and/or min zoom scale
- *
- * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
- *
- */
-public interface ZoomRestrictableGridInterface {
-
-	/**
-	 * The resolution is calculated by number of units in layer's crs / number of pixels.
-	 * null is allowed as return value.
-	 *
-	 * @return the maximum resolution this grid provides. (the smalles value)
-	 */
-	Double getMaxResolution();
-
-	/**
-	 * The resolution is calculated by number of units in layer's crs / number of pixels.
-	 * null is allowed as return value.
-	 *
-	 * @return the minimum resolution this grid provides. (the biggest value)
-	 */
-	Double getMinResolution();
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package skrueger.geotools;
+
+/**
+ * Classes that implement {@link ZoomRestrictableGridInterface} can be restricted to their max- and/or min zoom scale
+ *
+ * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
+ *
+ */
+public interface ZoomRestrictableGridInterface {
+
+	/**
+	 * The resolution is calculated by number of units in layer's crs / number of pixels.
+	 * null is allowed as return value.
+	 *
+	 * @return the maximum resolution this grid provides. (the smalles value)
+	 */
+	Double getMaxResolution();
+
+	/**
+	 * The resolution is calculated by number of units in layer's crs / number of pixels.
+	 * null is allowed as return value.
+	 *
+	 * @return the minimum resolution this grid provides. (the biggest value)
+	 */
+	Double getMinResolution();
+
+}

Modified: trunk/src/skrueger/geotools/io/GeoImportUtilURL.java
===================================================================
--- trunk/src/skrueger/geotools/io/GeoImportUtilURL.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/io/GeoImportUtilURL.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,171 +1,200 @@
-package skrueger.geotools.io;
-
-import java.awt.geom.Rectangle2D;
-import java.awt.image.BufferedImage;
-import java.io.IOException;
-import java.net.URL;
-
-import javax.imageio.IIOException;
-import javax.imageio.ImageIO;
-
-import org.apache.log4j.Logger;
-import org.geotools.coverage.grid.GridCoverage2D;
-import org.geotools.coverage.grid.GridCoverageFactory;
-import org.geotools.factory.Hints;
-import org.geotools.gce.geotiff.GeoTiffReader;
-import org.geotools.geometry.Envelope2D;
-import org.opengis.referencing.crs.CoordinateReferenceSystem;
-
-import schmitzm.geotools.io.GeoImportUtil;
-import schmitzm.io.IOUtil;
-
-/**
- * Erweiterungen von Martin's {@link GeoImportUtil} classe fuer die konsequente Benutzung mit {@link URL}s.
- * TODO Diese Klasse sollte vielleicht mit der {@link GeoImportUtil} zusammengefuegt werden.
- *
- * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
- *
- */
-public class GeoImportUtilURL extends GeoImportUtil {
-	final static private Logger LOGGER = Logger.getLogger(GeoImportUtilURL.class);
-
-	/**
-	 * Read a {@link GridCoverage2D} from an image file. .prj and .wld files are usually expected
-	 */
-	public static GridCoverage2D readGridFromImage(URL url) throws IOException {
-		return readGridFromImage(url, null);
-	}
-
-	/**
-	 * Read a {@link GridCoverage2D} from an image file. .wld file is usually expected also. The CRS can be given as the crs parameter. null is valid.
-	 *
-	 * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
-	 */
-	public static GridCoverage2D readGridFromImage(URL url,
-			CoordinateReferenceSystem crs) throws IOException {
-		GridCoverage2D gc = null;
-
-		BufferedImage im = ImageIO.read(url);
-		if (im == null)
-			throw new IIOException("No image reader found for this image type!");
-
-		// World-File einlesen
-		double[] tfwInfo = null;
-
-		for (WORLD_POSTFIXES pf : WORLD_POSTFIXES.values()){
-			if (tfwInfo == null) {
-				try {
-					tfwInfo = readWorldFile( IOUtil.changeUrlExt(url, pf.toString() ).openStream());
-				} catch (Exception e) {
-				}
-			}
-		}
-
-		if (tfwInfo == null)
-			throw new IllegalArgumentException(
-					"No georeferencing information found.\n"
-					+ "Attach a .wld file to "+url+"please.");
-
-		float w = (float) (im.getWidth() * tfwInfo[0]); // reale Breite =
-		// RasterSpalten *
-		// hor. Aufloesung
-		float h = (float) (im.getHeight() * (-tfwInfo[3])); // reale Hoehe =
-		// RasterZeilen
-		// * vert.
-		// Aufloesung
-		float x = (float) tfwInfo[4]; // Suedwestliche Ecke!
-		float y = (float) tfwInfo[5] - h; // Suedwestliche Ecke (im
-		// tfw-File steht die
-		// Nordwestliche!)
-		// ggf. Projektion einlesen
-		if (crs == null) {
-			crs = determineProjection( IOUtil.changeUrlExt(url, "prj") );
-		}
-		Envelope2D envelope = new Envelope2D(crs, new Rectangle2D.Float(x, y,
-				w, h));
-		// WICHTIG: Name des Rasters sollte Leer-String sein, da ansonsten
-		// das
-		// Coloring des Rasters nicht klappt.
-		// --> Name der Categories und ColorMapEntries-Labels muss (warum auch immer) mit dem Namen
-		// des Rasters uebereinstimmen!!!
-		gc = new GridCoverageFactory().create("", im, envelope);
-
-		return gc;
-	}
-
-	/**
-	 * Diese Methode importiert ein Raster aus einer Datei im GeoTIFF-Format.
-	 * Zunaechst wird versucht, die Geo-Informationen (Referenz+CRS) aus den
-	 * TIFF-Metadaten zu ermitteln. Ist dies nicht erfolgreich, werden ein
-	 * gleichnamiges World-File (.tfw) und Projection-File (.prj) herangezogen.
-	 * Als Projektion (.prj) ist sowohl ein EPSG-Code "EPSG:...", als auch eine
-	 * WKT-Definition erlaubt. Kann kein CRS ermitteln werden, wird
-	 * {@link #DEFAULT_CRS} als CRS verwendet.
-	 *
-	 * @param geotiffURL
-	 *            URL to GeoTIFF-File
-	 * @param crs
-	 *            erzwungenes CoordinateReferenceSystem fuer das Raster (kann
-	 *            {@code null} sein)
-	 * @throws java.lang.Exception
-	 *             bei irgendeinem Fehler
-	 *
-	 * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
-	 *         (University of Bonn/Germany)
-	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
-	 */
-	public static GridCoverage2D readGridFromGeoTiff(URL geotiffURL,
-			CoordinateReferenceSystem crs) throws Exception {
-		GridCoverage2D gc = null;
-		LOGGER.debug("Loading GeoTiff from URL = " + geotiffURL + " now.");
-
-		// Versuchen Geo-Information aus Tiff zu lesen
-		try {
-
-			// Wenn CRS angegeben, dieses durch Hint erzwingen
-			Hints hints = new Hints(null);
-
-			if (crs != null)
-				hints.put(Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM, crs);
-			// Reader (mit Metadaten) erzeugen
-
-			LOGGER.debug("First try to create GeoTiff reader");
-
-			/**
-			 * Attention, Attention: The GeoTiffReader fails for URLs like:
-			 * 
-			 * jar:file:/home/sdsd/ad/atlas/raster_textur00949608497.jar!/ad/data/raster_textur00949608497/textur.tif
-			 * 
-			 * It should be converted to something like:
-			 * jar:http:///atlas/raster_textur00949608497.jar!/ad/data/raster_textur00949608497/textur.tif
-			 * jar:http://www.wikisquare.de/atlas/raster_textur00949608497.jar!/ad/data/raster_textur00949608497/textur.tif
-			 */
-			GeoTiffReader reader = new GeoTiffReader(geotiffURL, hints);
-
-			// Wenn kein Referenzsystem vorhanden, versuchen ein prj-File zu
-			// verwenden
-			if (reader.getOriginalEnvelope().getCoordinateReferenceSystem() == null) {
-				LOGGER
-						.warn("Second try because no projection information found in GeoTIFF. Using prj-file...");
-
-				final CoordinateReferenceSystem determineProjection = determineProjection(IOUtil.changeUrlExt(
-						geotiffURL, "prj"));
-				hints.put(Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM,
-						determineProjection);
-				reader = new GeoTiffReader(geotiffURL, hints);
-			}
-			gc = (GridCoverage2D) reader.read(null);
-			LOGGER.debug("... was successfull!");
-		} catch (UnsupportedOperationException err) {
-			LOGGER.debug("... failed.");
-			LOGGER.error(err);
-			LOGGER.warn("No GeoTIFF information found. Using simple image + world- and prj-file...");
-			LOGGER.debug("Second try to use readGridFromImage()");
-			gc = readGridFromImage(geotiffURL, crs); //TODO style
-		}
-		return gc;
-	}
-
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package skrueger.geotools.io;
+
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.net.URL;
+
+import javax.imageio.IIOException;
+import javax.imageio.ImageIO;
+
+import org.apache.log4j.Logger;
+import org.geotools.coverage.grid.GridCoverage2D;
+import org.geotools.coverage.grid.GridCoverageFactory;
+import org.geotools.factory.Hints;
+import org.geotools.gce.geotiff.GeoTiffReader;
+import org.geotools.geometry.Envelope2D;
+import org.opengis.referencing.crs.CoordinateReferenceSystem;
+
+import schmitzm.geotools.io.GeoImportUtil;
+import schmitzm.io.IOUtil;
+
+/**
+ * Erweiterungen von Martin's {@link GeoImportUtil} classe fuer die konsequente Benutzung mit {@link URL}s.
+ * TODO Diese Klasse sollte vielleicht mit der {@link GeoImportUtil} zusammengefuegt werden.
+ *
+ * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
+ *
+ */
+public class GeoImportUtilURL extends GeoImportUtil {
+	final static private Logger LOGGER = Logger.getLogger(GeoImportUtilURL.class);
+
+	/**
+	 * Read a {@link GridCoverage2D} from an image file. .prj and .wld files are usually expected
+	 */
+	public static GridCoverage2D readGridFromImage(URL url) throws IOException {
+		return readGridFromImage(url, null);
+	}
+
+	/**
+	 * Read a {@link GridCoverage2D} from an image file. .wld file is usually expected also. The CRS can be given as the crs parameter. null is valid.
+	 *
+	 * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a> (University of Bonn/Germany)
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
+	 */
+	public static GridCoverage2D readGridFromImage(URL url,
+			CoordinateReferenceSystem crs) throws IOException {
+		GridCoverage2D gc = null;
+
+		BufferedImage im = ImageIO.read(url);
+		if (im == null)
+			throw new IIOException("No image reader found for this image type!");
+
+		// World-File einlesen
+		double[] tfwInfo = null;
+
+		for (WORLD_POSTFIXES pf : WORLD_POSTFIXES.values()){
+			if (tfwInfo == null) {
+				try {
+					tfwInfo = readWorldFile( IOUtil.changeUrlExt(url, pf.toString() ).openStream());
+				} catch (Exception e) {
+				}
+			}
+		}
+
+		if (tfwInfo == null)
+			throw new IllegalArgumentException(
+					"No georeferencing information found.\n"
+					+ "Attach a .wld file to "+url+"please.");
+
+		float w = (float) (im.getWidth() * tfwInfo[0]); // reale Breite =
+		// RasterSpalten *
+		// hor. Aufloesung
+		float h = (float) (im.getHeight() * (-tfwInfo[3])); // reale Hoehe =
+		// RasterZeilen
+		// * vert.
+		// Aufloesung
+		float x = (float) tfwInfo[4]; // Suedwestliche Ecke!
+		float y = (float) tfwInfo[5] - h; // Suedwestliche Ecke (im
+		// tfw-File steht die
+		// Nordwestliche!)
+		// ggf. Projektion einlesen
+		if (crs == null) {
+			crs = determineProjection( IOUtil.changeUrlExt(url, "prj") );
+		}
+		Envelope2D envelope = new Envelope2D(crs, new Rectangle2D.Float(x, y,
+				w, h));
+		// WICHTIG: Name des Rasters sollte Leer-String sein, da ansonsten
+		// das
+		// Coloring des Rasters nicht klappt.
+		// --> Name der Categories und ColorMapEntries-Labels muss (warum auch immer) mit dem Namen
+		// des Rasters uebereinstimmen!!!
+		gc = new GridCoverageFactory().create("", im, envelope);
+
+		return gc;
+	}
+
+	/**
+	 * Diese Methode importiert ein Raster aus einer Datei im GeoTIFF-Format.
+	 * Zunaechst wird versucht, die Geo-Informationen (Referenz+CRS) aus den
+	 * TIFF-Metadaten zu ermitteln. Ist dies nicht erfolgreich, werden ein
+	 * gleichnamiges World-File (.tfw) und Projection-File (.prj) herangezogen.
+	 * Als Projektion (.prj) ist sowohl ein EPSG-Code "EPSG:...", als auch eine
+	 * WKT-Definition erlaubt. Kann kein CRS ermitteln werden, wird
+	 * {@link #DEFAULT_CRS} als CRS verwendet.
+	 *
+	 * @param geotiffURL
+	 *            URL to GeoTIFF-File
+	 * @param crs
+	 *            erzwungenes CoordinateReferenceSystem fuer das Raster (kann
+	 *            {@code null} sein)
+	 * @throws java.lang.Exception
+	 *             bei irgendeinem Fehler
+	 *
+	 * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+	 *         (University of Bonn/Germany)
+	 * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
+	 */
+	public static GridCoverage2D readGridFromGeoTiff(URL geotiffURL,
+			CoordinateReferenceSystem crs) throws Exception {
+		GridCoverage2D gc = null;
+		LOGGER.debug("Loading GeoTiff from URL = " + geotiffURL + " now.");
+
+		// Versuchen Geo-Information aus Tiff zu lesen
+		try {
+
+			// Wenn CRS angegeben, dieses durch Hint erzwingen
+			Hints hints = new Hints(null);
+
+			if (crs != null)
+				hints.put(Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM, crs);
+			// Reader (mit Metadaten) erzeugen
+
+			LOGGER.debug("First try to create GeoTiff reader");
+
+			/**
+			 * Attention, Attention: The GeoTiffReader fails for URLs like:
+			 * 
+			 * jar:file:/home/sdsd/ad/atlas/raster_textur00949608497.jar!/ad/data/raster_textur00949608497/textur.tif
+			 * 
+			 * It should be converted to something like:
+			 * jar:http:///atlas/raster_textur00949608497.jar!/ad/data/raster_textur00949608497/textur.tif
+			 * jar:http://www.wikisquare.de/atlas/raster_textur00949608497.jar!/ad/data/raster_textur00949608497/textur.tif
+			 */
+			GeoTiffReader reader = new GeoTiffReader(geotiffURL, hints);
+
+			// Wenn kein Referenzsystem vorhanden, versuchen ein prj-File zu
+			// verwenden
+			if (reader.getOriginalEnvelope().getCoordinateReferenceSystem() == null) {
+				LOGGER
+						.warn("Second try because no projection information found in GeoTIFF. Using prj-file...");
+
+				final CoordinateReferenceSystem determineProjection = determineProjection(IOUtil.changeUrlExt(
+						geotiffURL, "prj"));
+				hints.put(Hints.DEFAULT_COORDINATE_REFERENCE_SYSTEM,
+						determineProjection);
+				reader = new GeoTiffReader(geotiffURL, hints);
+			}
+			gc = (GridCoverage2D) reader.read(null);
+			LOGGER.debug("... was successfull!");
+		} catch (UnsupportedOperationException err) {
+			LOGGER.debug("... failed.");
+			LOGGER.error(err);
+			LOGGER.warn("No GeoTIFF information found. Using simple image + world- and prj-file...");
+			LOGGER.debug("Second try to use readGridFromImage()");
+			gc = readGridFromImage(geotiffURL, crs); //TODO style
+		}
+		return gc;
+	}
+
+
+}

Modified: trunk/src/skrueger/geotools/labelsearch/LabelSearch.java
===================================================================
--- trunk/src/skrueger/geotools/labelsearch/LabelSearch.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/labelsearch/LabelSearch.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,3 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package skrueger.geotools.labelsearch;
 
 import java.io.IOException;

Modified: trunk/src/skrueger/geotools/labelsearch/SearchMapDialog.java
===================================================================
--- trunk/src/skrueger/geotools/labelsearch/SearchMapDialog.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/labelsearch/SearchMapDialog.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,3 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 /*
  * SearchMapDialog.java
  *
@@ -209,4 +238,4 @@
 		pack();
 	}
 
-}
\ No newline at end of file
+}

Modified: trunk/src/skrueger/geotools/labelsearch/SearchResult.java
===================================================================
--- trunk/src/skrueger/geotools/labelsearch/SearchResult.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/labelsearch/SearchResult.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,3 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package skrueger.geotools.labelsearch;
 
 import java.util.Map;

Modified: trunk/src/skrueger/geotools/labelsearch/SearchResultFeature.java
===================================================================
--- trunk/src/skrueger/geotools/labelsearch/SearchResultFeature.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/labelsearch/SearchResultFeature.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,3 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package skrueger.geotools.labelsearch;
 
 import javax.swing.SwingUtilities;

Modified: trunk/src/skrueger/geotools/labelsearch/SearchResultTableModel.java
===================================================================
--- trunk/src/skrueger/geotools/labelsearch/SearchResultTableModel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/labelsearch/SearchResultTableModel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,3 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package skrueger.geotools.labelsearch;
 
 import java.util.List;

Modified: trunk/src/skrueger/geotools/labelsearch/Snippet.java
===================================================================
--- trunk/src/skrueger/geotools/labelsearch/Snippet.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/labelsearch/Snippet.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,3 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package skrueger.geotools.labelsearch;
 
 import java.util.Locale;

Modified: trunk/src/skrueger/geotools/labelsearch/labelsearch.properties
===================================================================
--- trunk/src/skrueger/geotools/labelsearch/labelsearch.properties	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/labelsearch/labelsearch.properties	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,3 +1,32 @@
+##########
+#Copyright (c) 2009 Martin O. J. Schmitz.
+#
+#This file is part of the SCHMITZM library - a collection of utility 
+#classes based on Java 1.6, focussing (not only) on Java Swing 
+#and the Geotools library.
+#
+#The SCHMITZM project is hosted at:
+#http://wald.intevation.org/projects/schmitzm/
+#
+#This program is free software; you can redistribute it and/or
+#modify it under the terms of the GNU Lesser General Public License
+#as published by the Free Software Foundation; either version 3
+#of the License, or (at your option) any later version.
+#
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+#
+#You should have received a copy of the GNU Lesser General Public License (license.txt)
+#along with this program; if not, write to the Free Software
+#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#or try this link: http://www.gnu.org/licenses/lgpl.html
+#
+#Contributors:
+#    Martin O. J. Schmitz - initial API and implementation
+#    Stefan A. Krüger - additional utility classes
+##########
 SearchMapDialog.Results.Column.Layer=found in
 SearchMapDialog.Results.Column.Name=name
 SearchMapDialog.resultsTable.tt=Click on a result to show it. 

Modified: trunk/src/skrueger/geotools/labelsearch/labelsearch_de.properties
===================================================================
--- trunk/src/skrueger/geotools/labelsearch/labelsearch_de.properties	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/labelsearch/labelsearch_de.properties	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,3 +1,32 @@
+##########
+#Copyright (c) 2009 Martin O. J. Schmitz.
+#
+#This file is part of the SCHMITZM library - a collection of utility 
+#classes based on Java 1.6, focussing (not only) on Java Swing 
+#and the Geotools library.
+#
+#The SCHMITZM project is hosted at:
+#http://wald.intevation.org/projects/schmitzm/
+#
+#This program is free software; you can redistribute it and/or
+#modify it under the terms of the GNU Lesser General Public License
+#as published by the Free Software Foundation; either version 3
+#of the License, or (at your option) any later version.
+#
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+#
+#You should have received a copy of the GNU Lesser General Public License (license.txt)
+#along with this program; if not, write to the Free Software
+#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#or try this link: http://www.gnu.org/licenses/lgpl.html
+#
+#Contributors:
+#    Martin O. J. Schmitz - initial API and implementation
+#    Stefan A. Krüger - additional utility classes
+##########
 SearchMapDialog.Results.Column.Layer=Gefunden in
 SearchMapDialog.Results.Column.Name=Name
 SearchMapDialog.resultsTable.tt=Klicken Sie auf ein Ergebnis um es anzuzeigen.
@@ -3,3 +32,3 @@
 SearchMapDialog.searchString.Label=Suchbegriff eingeben:
 SearchMapDialog.searchString.tt=Geben Sie den Suchbegriff ein und drücken Sie [Enter]
-SearchMapDialog.title=Durchsuche Karte: ${0}
\ No newline at end of file
+SearchMapDialog.title=Durchsuche Karte: ${0}

Modified: trunk/src/skrueger/geotools/labelsearch/labelsearch_fr.properties
===================================================================
--- trunk/src/skrueger/geotools/labelsearch/labelsearch_fr.properties	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/labelsearch/labelsearch_fr.properties	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,3 +1,32 @@
+##########
+#Copyright (c) 2009 Martin O. J. Schmitz.
+#
+#This file is part of the SCHMITZM library - a collection of utility 
+#classes based on Java 1.6, focussing (not only) on Java Swing 
+#and the Geotools library.
+#
+#The SCHMITZM project is hosted at:
+#http://wald.intevation.org/projects/schmitzm/
+#
+#This program is free software; you can redistribute it and/or
+#modify it under the terms of the GNU Lesser General Public License
+#as published by the Free Software Foundation; either version 3
+#of the License, or (at your option) any later version.
+#
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+#
+#You should have received a copy of the GNU Lesser General Public License (license.txt)
+#along with this program; if not, write to the Free Software
+#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#or try this link: http://www.gnu.org/licenses/lgpl.html
+#
+#Contributors:
+#    Martin O. J. Schmitz - initial API and implementation
+#    Stefan A. Krüger - additional utility classes
+##########
 SearchMapDialog.Results.Column.Layer=Retrouvés dans
 SearchMapDialog.Results.Column.Name=Nom
 SearchMapDialog.resultsTable.tt=Cliquer sur un résultat pour l`afficher.
@@ -3,3 +32,3 @@
 SearchMapDialog.searchString.Label=Entrer le domaine de recherche:
 SearchMapDialog.searchString.tt=Saisir le domaine de recherche et appuyer sur [Enter]
-SearchMapDialog.title=Rechercher dans la carte: ${0}
\ No newline at end of file
+SearchMapDialog.title=Rechercher dans la carte: ${0}

Modified: trunk/src/skrueger/geotools/resource/locales/mapPaneToolbar.properties
===================================================================
--- trunk/src/skrueger/geotools/resource/locales/mapPaneToolbar.properties	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/resource/locales/mapPaneToolbar.properties	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,3 +1,32 @@
+##########
+#Copyright (c) 2009 Martin O. J. Schmitz.
+#
+#This file is part of the SCHMITZM library - a collection of utility 
+#classes based on Java 1.6, focussing (not only) on Java Swing 
+#and the Geotools library.
+#
+#The SCHMITZM project is hosted at:
+#http://wald.intevation.org/projects/schmitzm/
+#
+#This program is free software; you can redistribute it and/or
+#modify it under the terms of the GNU Lesser General Public License
+#as published by the Free Software Foundation; either version 3
+#of the License, or (at your option) any later version.
+#
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+#
+#You should have received a copy of the GNU Lesser General Public License (license.txt)
+#along with this program; if not, write to the Free Software
+#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#or try this link: http://www.gnu.org/licenses/lgpl.html
+#
+#Contributors:
+#    Martin O. J. Schmitz - initial API and implementation
+#    Stefan A. Krüger - additional utility classes
+##########
 MapPaneButtons.Pan.TT=Move the visible map extend
 MapPaneButtons.Info.TT=Get information about objects 
 MapPaneButtons.ZoomIn.TT=Zoom nearer to the map
@@ -3,3 +32,3 @@
 MapPaneButtons.ZoomOut.TT=Zoom away from the map
 MapPaneButtons.LastZoom.TT=Go to last map extend
-MapPaneButtons.NextZoom.TT=Go to next map extend
\ No newline at end of file
+MapPaneButtons.NextZoom.TT=Go to next map extend

Modified: trunk/src/skrueger/geotools/resource/locales/mapPaneToolbar_de.properties
===================================================================
--- trunk/src/skrueger/geotools/resource/locales/mapPaneToolbar_de.properties	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/resource/locales/mapPaneToolbar_de.properties	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,3 +1,32 @@
+##########
+#Copyright (c) 2009 Martin O. J. Schmitz.
+#
+#This file is part of the SCHMITZM library - a collection of utility 
+#classes based on Java 1.6, focussing (not only) on Java Swing 
+#and the Geotools library.
+#
+#The SCHMITZM project is hosted at:
+#http://wald.intevation.org/projects/schmitzm/
+#
+#This program is free software; you can redistribute it and/or
+#modify it under the terms of the GNU Lesser General Public License
+#as published by the Free Software Foundation; either version 3
+#of the License, or (at your option) any later version.
+#
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+#
+#You should have received a copy of the GNU Lesser General Public License (license.txt)
+#along with this program; if not, write to the Free Software
+#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#or try this link: http://www.gnu.org/licenses/lgpl.html
+#
+#Contributors:
+#    Martin O. J. Schmitz - initial API and implementation
+#    Stefan A. Krüger - additional utility classes
+##########
 MapPaneButtons.Pan.TT=Karte verschieben
 MapPaneButtons.Info.TT=Informationen zu Objekten abfragen 
 MapPaneButtons.ZoomIn.TT=Auf einen Auschnitt zoomen
@@ -3,3 +32,3 @@
 MapPaneButtons.ZoomOut.TT=Aus der Karte herauszoomen
 MapPaneButtons.LastZoom.TT=Letzten Kartenausschnitt wiederherstellen 
-MapPaneButtons.NextZoom.TT=Nächsten Kartenausschnitt wiederherstellen
\ No newline at end of file
+MapPaneButtons.NextZoom.TT=Nächsten Kartenausschnitt wiederherstellen

Modified: trunk/src/skrueger/geotools/resource/locales/mapPaneToolbar_fr.properties
===================================================================
--- trunk/src/skrueger/geotools/resource/locales/mapPaneToolbar_fr.properties	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/resource/locales/mapPaneToolbar_fr.properties	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,3 +1,32 @@
+##########
+#Copyright (c) 2009 Martin O. J. Schmitz.
+#
+#This file is part of the SCHMITZM library - a collection of utility 
+#classes based on Java 1.6, focussing (not only) on Java Swing 
+#and the Geotools library.
+#
+#The SCHMITZM project is hosted at:
+#http://wald.intevation.org/projects/schmitzm/
+#
+#This program is free software; you can redistribute it and/or
+#modify it under the terms of the GNU Lesser General Public License
+#as published by the Free Software Foundation; either version 3
+#of the License, or (at your option) any later version.
+#
+#This program is distributed in the hope that it will be useful,
+#but WITHOUT ANY WARRANTY; without even the implied warranty of
+#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#GNU General Public License for more details.
+#
+#You should have received a copy of the GNU Lesser General Public License (license.txt)
+#along with this program; if not, write to the Free Software
+#Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+#or try this link: http://www.gnu.org/licenses/lgpl.html
+#
+#Contributors:
+#    Martin O. J. Schmitz - initial API and implementation
+#    Stefan A. Krüger - additional utility classes
+##########
 MapPaneButtons.Pan.TT=Déplacer la catre.
 MapPaneButtons.Info.TT=Avoir des informations sur les objects.
 MapPaneButtons.ZoomIn.TT=Effectuer un zoom d'un extrait oder faire un gros plan d'un extrait.
@@ -3,3 +32,3 @@
 MapPaneButtons.ZoomOut.TT=Effectuer un zoom d'un extrait de la carte oder faire un gros plan d'un extrait de carte.
 MapPaneButtons.LastZoom.TT=Restaurer le dernier extrait de la carte.
-MapPaneButtons.NextZoom.TT=Restaurer le prochain extrait de la carte.
\ No newline at end of file
+MapPaneButtons.NextZoom.TT=Restaurer le prochain extrait de la carte.

Modified: trunk/src/skrueger/geotools/selection/ChartSelectionSynchronizer.java
===================================================================
--- trunk/src/skrueger/geotools/selection/ChartSelectionSynchronizer.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/selection/ChartSelectionSynchronizer.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,128 +1,146 @@
-/** SCHMITZM - This file is part of the java library of Martin O.J. Schmitz (SCHMITZM)
-
-    This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.
-    This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
-    You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
-
-    Diese Bibliothek ist freie Software; Sie dürfen sie unter den Bedingungen der GNU Lesser General Public License, wie von der Free Software Foundation veröffentlicht, weiterverteilen und/oder modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer Option) jeder späteren Version.
-    Diese Bibliothek wird in der Hoffnung weiterverbreitet, daß sie nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser General Public License.
-    Sie sollten eine Kopie der GNU Lesser General Public License zusammen mit dieser Bibliothek erhalten haben; falls nicht, schreiben Sie an die Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110, USA.
- **/
-
-package skrueger.geotools.selection;
-
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.util.Vector;
-
-import org.jfree.data.general.Dataset;
-
-import schmitzm.jfree.chart.renderer.SelectionRenderer;
-import schmitzm.jfree.chart.selection.DatasetSelectionChangeEvent;
-import schmitzm.jfree.chart.selection.DatasetSelectionListener;
-import schmitzm.jfree.chart.selection.DatasetSelectionModel;
-import schmitzm.jfree.chart.selection.DatasetSelectionModelProvider;
-import schmitzm.jfree.feature.FeatureDatasetSelectionModel;
-
-/**
- * This class keeps the selection of a {@link Dataset} (based on feature
- * attributes) synchronized with the {@link StyledLayerSelectionModel} of a layer.
- * This is done by implementing:
- * <ul>
- * <li>a {@link PropertyChangeListener} which listens to the
- * {@link StyledLayerSelectionModel} and accordingly changes the {@link SelectionRenderer}
- * selection</li>
- * <li>a {@link DatasetSelectionModel} which listens to the {@link SelectionRenderer} and
- * accordingly changes the {@link StyledLayerSelectionModel} selection</li>
- * </ul>
- * After creating, the instance of this synchronizer must be added as listener
- * to both, the {@link StyledLayerSelectionModel} and the chart's
- * {@link DatasetSelectionModel} (e.g. the renderer).
- * @see DatasetSelectionModelProvider
- * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
- */
-public class ChartSelectionSynchronizer extends StyledLayerSelectionModelSynchronizer<StyledFeatureLayerSelectionModel>
-                                        implements DatasetSelectionListener {
-
-  /** Holds the chart datset to keep synchronized with the layer selection model. */
-  protected FeatureDatasetSelectionModel<?> datasetSelModel = null;
-
-  /**
-   * Creates a new synchronizer.
-   * @param layerSelModel
-   *             layer selection model to keep synchronized with the dataset
-   *             selection model
-   * @param datasetSelModel
-   *            dataset selection model to keep synchronized with the layer
-   *            selection model
-   */
-  public ChartSelectionSynchronizer(StyledFeatureLayerSelectionModel layerSelModel, FeatureDatasetSelectionModel<?> datasetSelModel) {
-    super(layerSelModel);
-    this.datasetSelModel = datasetSelModel;
-  }
-
-  /**
-   * Called by {@link StyledLayerSelectionModel} when the selection on other
-   * selection components (map, table, ...) has changed. When calling this
-   * method changes the dataset selection according to the
-   * {@link StyledLayerSelectionModel} selection.
-   * @param evt an event
-   */
-  @Override
-  public void propertyChange(PropertyChangeEvent evt) {
-    if (!(evt instanceof StyledLayerSelectionEvent))
-      return;
-    StyledLayerSelectionEvent selEvt = (StyledLayerSelectionEvent) evt;
-    // Only react on own layer and ignore events invoked by
-    // this component itself
-    if (selEvt.getEmitter() != layerSelModel || selectionChangeCausedByMe)
-        return;
-    // Apply new selection on chart (except this event is one of
-    // some more events)
-    Vector<String> newSelection = layerSelModel.getSelection();
-    if (newSelection == null)
-      return;
-
-    // Avoid event circles in valueChanged(..)
-    selectionChangeCausedByMe = true;
-
-    datasetSelModel.setValueIsAdjusting(true);
-    datasetSelModel.clearSelection();
-    for (String fID : newSelection)
-      datasetSelModel.setItemSelected(fID, true);
-    datasetSelModel.setValueIsAdjusting(false); // event is fired autmatically!
-
-    // Danger of event circles in valueChanged(..) banned
-    selectionChangeCausedByMe = false;
-  }
-
-  /**
-   * Called when the chart selection is changed by the user. When calling this
-   * method changes the selection of the {@link StyledLayerSelectionModel}.
-   * @param evt an event
-   */
-  @Override
-  public void selectionChanged(DatasetSelectionChangeEvent evt) {
-    // ignore event if it is part of multiple events
-    if (evt != null && evt.getSource().getValueIsAdjusting())
-        return;
-    // ignore event if it is caused by the ChartSelectionSynchronizer
-    if (selectionChangeCausedByMe)
-        return;
-
-    // Avoid event circles in propertyChange(..)
-    selectionChangeCausedByMe = true;
-
-    // reset the selection of the DpLayerSelectionModel
-    layerSelModel.setValueIsAdjusting(true);
-    layerSelModel.clearSelection();
-    for (String featureID : datasetSelModel.getSelectedFeatures())
-      layerSelModel.addSelection(featureID);
-    layerSelModel.setValueIsAdjusting(false);
-
-    // Danger of event circles in propertyChange(..) banned
-    selectionChangeCausedByMe = false;
-  }
-  
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package skrueger.geotools.selection;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.Vector;
+
+import org.jfree.data.general.Dataset;
+
+import schmitzm.jfree.chart.renderer.SelectionRenderer;
+import schmitzm.jfree.chart.selection.DatasetSelectionChangeEvent;
+import schmitzm.jfree.chart.selection.DatasetSelectionListener;
+import schmitzm.jfree.chart.selection.DatasetSelectionModel;
+import schmitzm.jfree.chart.selection.DatasetSelectionModelProvider;
+import schmitzm.jfree.feature.FeatureDatasetSelectionModel;
+
+/**
+ * This class keeps the selection of a {@link Dataset} (based on feature
+ * attributes) synchronized with the {@link StyledLayerSelectionModel} of a layer.
+ * This is done by implementing:
+ * <ul>
+ * <li>a {@link PropertyChangeListener} which listens to the
+ * {@link StyledLayerSelectionModel} and accordingly changes the {@link SelectionRenderer}
+ * selection</li>
+ * <li>a {@link DatasetSelectionModel} which listens to the {@link SelectionRenderer} and
+ * accordingly changes the {@link StyledLayerSelectionModel} selection</li>
+ * </ul>
+ * After creating, the instance of this synchronizer must be added as listener
+ * to both, the {@link StyledLayerSelectionModel} and the chart's
+ * {@link DatasetSelectionModel} (e.g. the renderer).
+ * @see DatasetSelectionModelProvider
+ * @author <a href="mailto:martin.schmitz at koeln.de">Martin Schmitz</a>
+ */
+public class ChartSelectionSynchronizer extends StyledLayerSelectionModelSynchronizer<StyledFeatureLayerSelectionModel>
+                                        implements DatasetSelectionListener {
+
+  /** Holds the chart datset to keep synchronized with the layer selection model. */
+  protected FeatureDatasetSelectionModel<?> datasetSelModel = null;
+
+  /**
+   * Creates a new synchronizer.
+   * @param layerSelModel
+   *             layer selection model to keep synchronized with the dataset
+   *             selection model
+   * @param datasetSelModel
+   *            dataset selection model to keep synchronized with the layer
+   *            selection model
+   */
+  public ChartSelectionSynchronizer(StyledFeatureLayerSelectionModel layerSelModel, FeatureDatasetSelectionModel<?> datasetSelModel) {
+    super(layerSelModel);
+    this.datasetSelModel = datasetSelModel;
+  }
+
+  /**
+   * Called by {@link StyledLayerSelectionModel} when the selection on other
+   * selection components (map, table, ...) has changed. When calling this
+   * method changes the dataset selection according to the
+   * {@link StyledLayerSelectionModel} selection.
+   * @param evt an event
+   */
+  @Override
+  public void propertyChange(PropertyChangeEvent evt) {
+    if (!(evt instanceof StyledLayerSelectionEvent))
+      return;
+    StyledLayerSelectionEvent selEvt = (StyledLayerSelectionEvent) evt;
+    // Only react on own layer and ignore events invoked by
+    // this component itself
+    if (selEvt.getEmitter() != layerSelModel || selectionChangeCausedByMe)
+        return;
+    // Apply new selection on chart (except this event is one of
+    // some more events)
+    Vector<String> newSelection = layerSelModel.getSelection();
+    if (newSelection == null)
+      return;
+
+    // Avoid event circles in valueChanged(..)
+    selectionChangeCausedByMe = true;
+
+    datasetSelModel.setValueIsAdjusting(true);
+    datasetSelModel.clearSelection();
+    for (String fID : newSelection)
+      datasetSelModel.setItemSelected(fID, true);
+    datasetSelModel.setValueIsAdjusting(false); // event is fired autmatically!
+
+    // Danger of event circles in valueChanged(..) banned
+    selectionChangeCausedByMe = false;
+  }
+
+  /**
+   * Called when the chart selection is changed by the user. When calling this
+   * method changes the selection of the {@link StyledLayerSelectionModel}.
+   * @param evt an event
+   */
+  @Override
+  public void selectionChanged(DatasetSelectionChangeEvent evt) {
+    // ignore event if it is part of multiple events
+    if (evt != null && evt.getSource().getValueIsAdjusting())
+        return;
+    // ignore event if it is caused by the ChartSelectionSynchronizer
+    if (selectionChangeCausedByMe)
+        return;
+
+    // Avoid event circles in propertyChange(..)
+    selectionChangeCausedByMe = true;
+
+    // reset the selection of the DpLayerSelectionModel
+    layerSelModel.setValueIsAdjusting(true);
+    layerSelModel.clearSelection();
+    for (String featureID : datasetSelModel.getSelectedFeatures())
+      layerSelModel.addSelection(featureID);
+    layerSelModel.setValueIsAdjusting(false);
+
+    // Danger of event circles in propertyChange(..) banned
+    selectionChangeCausedByMe = false;
+  }
+  
+
+}

Modified: trunk/src/skrueger/geotools/selection/FeatureMapLayerSelectionSynchronizer.java
===================================================================
--- trunk/src/skrueger/geotools/selection/FeatureMapLayerSelectionSynchronizer.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/selection/FeatureMapLayerSelectionSynchronizer.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,3 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 /** 
  Copyright 2008 Stefan Alfons Krüger 
  

Modified: trunk/src/skrueger/geotools/selection/StyledFeatureLayerSelectionModel.java
===================================================================
--- trunk/src/skrueger/geotools/selection/StyledFeatureLayerSelectionModel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/selection/StyledFeatureLayerSelectionModel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,3 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 /** 
  Copyright 2008 Stefan Alfons Krüger 
  

Modified: trunk/src/skrueger/geotools/selection/StyledLayerSelectionEvent.java
===================================================================
--- trunk/src/skrueger/geotools/selection/StyledLayerSelectionEvent.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/selection/StyledLayerSelectionEvent.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,3 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 /** 
  Copyright 2008 Stefan Alfons Krüger 
  

Modified: trunk/src/skrueger/geotools/selection/StyledLayerSelectionModel.java
===================================================================
--- trunk/src/skrueger/geotools/selection/StyledLayerSelectionModel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/selection/StyledLayerSelectionModel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,3 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 /**
  Copyright 2008 Stefan Alfons Krüger
 

Modified: trunk/src/skrueger/geotools/selection/StyledLayerSelectionModelSynchronizer.java
===================================================================
--- trunk/src/skrueger/geotools/selection/StyledLayerSelectionModelSynchronizer.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/selection/StyledLayerSelectionModelSynchronizer.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,3 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package skrueger.geotools.selection;
 
 import java.beans.PropertyChangeListener;

Modified: trunk/src/skrueger/geotools/selection/TableSelectionSynchronizer.java
===================================================================
--- trunk/src/skrueger/geotools/selection/TableSelectionSynchronizer.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/geotools/selection/TableSelectionSynchronizer.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,3 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 /** 
  Copyright 2008 Stefan Alfons Krüger 
  

Modified: trunk/src/skrueger/i8n/I8NUtil.java
===================================================================
--- trunk/src/skrueger/i8n/I8NUtil.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/i8n/I8NUtil.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,3 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package skrueger.i8n;
 
 import java.util.Locale;

Modified: trunk/src/skrueger/i8n/SwitchLanguageDialog.java
===================================================================
--- trunk/src/skrueger/i8n/SwitchLanguageDialog.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/i8n/SwitchLanguageDialog.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,261 +1,290 @@
-package skrueger.i8n;
-
-import java.awt.Component;
-import java.awt.GridBagConstraints;
-import java.awt.GridBagLayout;
-import java.awt.Insets;
-import java.awt.Window;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.MouseWheelListener;
-import java.util.List;
-import java.util.Locale;
-
-import javax.swing.DefaultComboBoxModel;
-import javax.swing.ImageIcon;
-import javax.swing.JButton;
-import javax.swing.JComboBox;
-import javax.swing.JDialog;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-
-import org.apache.log4j.Logger;
-
-import schmitzm.swing.SwingUtil;
-import skrueger.swing.OkButton;
-import skrueger.swing.TranslationEditJPanel;
-
-/**
- * This dialog ask the user to select one of list of given languages. The dialog
- * is modal and not visible after construction.
- * 
- * @author Stefan A. Krueger
- */
-public class SwitchLanguageDialog extends JDialog {
-	protected Logger LOGGER = Logger.getLogger(SwitchLanguageDialog.class);
-
-	private static final long serialVersionUID = 1L;
-
-	private JPanel jContentPane = null;
-
-	private JLabel jLabelFlagimage = null;
-
-	private JPanel jPanel = null;
-
-	private JButton jButton = null;
-
-	private JPanel jPanel1 = null;
-
-	private JLabel jLabel = null;
-
-	private JComboBox jComboBox = null;
-
-	private final List<String> languages;
-
-	/**
-	 * 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
-	 */
-	public SwitchLanguageDialog(final Component owner,
-			final List<String> languages) {
-		super(SwingUtil.getParentWindow(owner));
-		this.languages = languages;
-
-		Translation.setActiveLang(languages.get(0));
-
-		if (languages.size() == 1) {
-			LOGGER.debug("Only language '" + languages.get(0)
-					+ "' is available. It has been selected automatically.");
-			return;
-		}
-
-		initialize();
-	}
-
-	/**
-	 * This method initializes this
-	 * 
-	 * @return void
-	 */
-	private void initialize() {
-		this.setContentPane(getJContentPane());
-		setModal(true);
-		SwingUtil.centerFrameOnScreenRandom(this);
-
-		setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
-
-		pack();
-	}
-
-	/**
-	 * This method initializes jContentPane
-	 * 
-	 * @return javax.swing.JPanel
-	 */
-	private JPanel getJContentPane() {
-		if (jContentPane == null) {
-			final GridBagConstraints gridBagConstraints11 = new GridBagConstraints();
-			gridBagConstraints11.gridx = 1;
-			gridBagConstraints11.fill = GridBagConstraints.HORIZONTAL;
-			gridBagConstraints11.gridy = 1;
-			final GridBagConstraints gridBagConstraints3 = new GridBagConstraints();
-			gridBagConstraints3.gridx = 1;
-			gridBagConstraints3.fill = GridBagConstraints.HORIZONTAL;
-			gridBagConstraints3.gridy = 2;
-			final GridBagConstraints gridBagConstraints1 = new GridBagConstraints();
-			gridBagConstraints1.gridx = 0;
-			gridBagConstraints1.fill = GridBagConstraints.BOTH;
-			gridBagConstraints1.gridwidth = 2;
-			gridBagConstraints1.anchor = GridBagConstraints.NORTH;
-			gridBagConstraints1.gridy = 0;
-			jLabelFlagimage = new JLabel(new ImageIcon(
-					TranslationEditJPanel.class
-							.getResource("resource/flags.jpg")));
-			jContentPane = new JPanel();
-			jContentPane.setLayout(new GridBagLayout());
-			jContentPane.add(jLabelFlagimage, gridBagConstraints1);
-			jContentPane.add(getJPanel(), gridBagConstraints3);
-			jContentPane.add(getJPanel1(), gridBagConstraints11);
-		}
-		return jContentPane;
-	}
-
-	/**
-	 * This method initializes jPanel
-	 * 
-	 * @return javax.swing.JPanel
-	 */
-	private JPanel getJPanel() {
-		if (jPanel == null) {
-			final GridBagConstraints gridBagConstraints4 = new GridBagConstraints();
-			gridBagConstraints4.gridx = 0;
-			gridBagConstraints4.anchor = GridBagConstraints.EAST;
-			gridBagConstraints4.weightx = 1.0;
-			gridBagConstraints4.insets = new Insets(5, 5, 5, 5);
-			gridBagConstraints4.gridy = 0;
-			jPanel = new JPanel();
-			jPanel.setLayout(new GridBagLayout());
-			jPanel.add(getJButton(), gridBagConstraints4);
-		}
-		return jPanel;
-	}
-
-	/**
-	 * This method initializes jButton
-	 * 
-	 * @return javax.swing.JButton
-	 */
-	private JButton getJButton() {
-		if (jButton == null) {
-			jButton = new OkButton();
-			jButton.setEnabled(false);
-
-			jButton.addActionListener(new ActionListener() {
-
-				public void actionPerformed(ActionEvent e) {
-					dispose();
-				}
-
-			});
-		}
-		return jButton;
-	}
-
-	/**
-	 * This method initializes jPanel1
-	 * 
-	 * @return javax.swing.JPanel
-	 */
-	private JPanel getJPanel1() {
-		if (jPanel1 == null) {
-			final GridBagConstraints gridBagConstraints2 = new GridBagConstraints();
-			gridBagConstraints2.fill = GridBagConstraints.VERTICAL;
-			gridBagConstraints2.gridy = 0;
-			gridBagConstraints2.weightx = 1.0;
-			gridBagConstraints2.insets = new Insets(5, 5, 5, 5);
-			gridBagConstraints2.anchor = GridBagConstraints.WEST;
-			gridBagConstraints2.gridx = 1;
-			final GridBagConstraints gridBagConstraints = new GridBagConstraints();
-			gridBagConstraints.gridx = 0;
-			gridBagConstraints.insets = new Insets(0, 5, 0, 0);
-			gridBagConstraints.gridy = 0;
-			jLabel = new JLabel();
-			jLabel.setText("Select language: "); // i8n!?! Maybe replace with an
-													// icon of an index finger
-			jPanel1 = new JPanel();
-			jPanel1.setLayout(new GridBagLayout());
-			jPanel1.add(jLabel, gridBagConstraints);
-			jPanel1.add(getJComboBox(), gridBagConstraints2);
-		}
-		return jPanel1;
-	}
-
-	/**
-	 * This method initializes jComboBox
-	 * 
-	 * @return javax.swing.JComboBox
-	 */
-	private JComboBox getJComboBox() {
-		if (jComboBox == null) {
-			jComboBox = new JComboBox();
-
-			jComboBox.addMouseWheelListener(new MouseWheelListener() {
-				public void mouseWheelMoved(java.awt.event.MouseWheelEvent e) {
-
-					if ((e.getWheelRotation() < 0)) {
-						if (jComboBox.getSelectedIndex() < jComboBox
-								.getItemCount() - 1)
-							jComboBox.setSelectedIndex(jComboBox
-									.getSelectedIndex() + 1);
-					} else {
-						if (jComboBox.getSelectedIndex() > 0)
-							jComboBox.setSelectedIndex(jComboBox
-									.getSelectedIndex() - 1);
-					}
-				}
-			});
-
-			String[] langNames = new String[languages.size() + 1];
-			for (int i = 0; i < languages.size(); i++) {
-
-				Locale locale = I8NUtil.getLocaleFor(languages.get(i));
-
-				langNames[i] = locale.getDisplayLanguage(locale) + " / "
-						+ locale.getDisplayLanguage() + " / "
-						+ languages.get(i);
-			}
-			langNames[languages.size()] = "?";
-
-			jComboBox.setModel(new DefaultComboBoxModel(langNames));
-			jComboBox.setSelectedItem(langNames[languages.size()]);
-
-			jComboBox.addActionListener(new ActionListener() {
-
-				public void actionPerformed(final ActionEvent e) {
-					if (jComboBox.getSelectedIndex() == languages.size()) {
-						getJButton().setEnabled(false);
-						return;
-					}
-
-					String l = languages.get(jComboBox.getSelectedIndex());
-					try {
-						Translation.setActiveLang(l);
-
-						getJButton().setEnabled(true);
-					} catch (java.lang.IllegalArgumentException ee) {
-						LOGGER.warn("The language " + l + " is not valid", ee);
-						getJButton().setEnabled(false);
-					}
-
-				}
-
-			});
-		}
-		return jComboBox;
-	}
-
-} // @jve:decl-index=0:visual-constraint="0,0"
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package skrueger.i8n;
+
+import java.awt.Component;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.Insets;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseWheelListener;
+import java.util.List;
+import java.util.Locale;
+
+import javax.swing.DefaultComboBoxModel;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+import org.apache.log4j.Logger;
+
+import schmitzm.swing.SwingUtil;
+import skrueger.swing.OkButton;
+import skrueger.swing.TranslationEditJPanel;
+
+/**
+ * This dialog ask the user to select one of list of given languages. The dialog
+ * is modal and not visible after construction.
+ * 
+ * @author Stefan A. Krueger
+ */
+public class SwitchLanguageDialog extends JDialog {
+	protected Logger LOGGER = Logger.getLogger(SwitchLanguageDialog.class);
+
+	private static final long serialVersionUID = 1L;
+
+	private JPanel jContentPane = null;
+
+	private JLabel jLabelFlagimage = null;
+
+	private JPanel jPanel = null;
+
+	private JButton jButton = null;
+
+	private JPanel jPanel1 = null;
+
+	private JLabel jLabel = null;
+
+	private JComboBox jComboBox = null;
+
+	private final List<String> languages;
+
+	/**
+	 * 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
+	 */
+	public SwitchLanguageDialog(final Component owner,
+			final List<String> languages) {
+		super(SwingUtil.getParentWindow(owner));
+		this.languages = languages;
+
+		Translation.setActiveLang(languages.get(0));
+
+		if (languages.size() == 1) {
+			LOGGER.debug("Only language '" + languages.get(0)
+					+ "' is available. It has been selected automatically.");
+			return;
+		}
+
+		initialize();
+	}
+
+	/**
+	 * This method initializes this
+	 * 
+	 * @return void
+	 */
+	private void initialize() {
+		this.setContentPane(getJContentPane());
+		setModal(true);
+		SwingUtil.centerFrameOnScreenRandom(this);
+
+		setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
+
+		pack();
+	}
+
+	/**
+	 * This method initializes jContentPane
+	 * 
+	 * @return javax.swing.JPanel
+	 */
+	private JPanel getJContentPane() {
+		if (jContentPane == null) {
+			final GridBagConstraints gridBagConstraints11 = new GridBagConstraints();
+			gridBagConstraints11.gridx = 1;
+			gridBagConstraints11.fill = GridBagConstraints.HORIZONTAL;
+			gridBagConstraints11.gridy = 1;
+			final GridBagConstraints gridBagConstraints3 = new GridBagConstraints();
+			gridBagConstraints3.gridx = 1;
+			gridBagConstraints3.fill = GridBagConstraints.HORIZONTAL;
+			gridBagConstraints3.gridy = 2;
+			final GridBagConstraints gridBagConstraints1 = new GridBagConstraints();
+			gridBagConstraints1.gridx = 0;
+			gridBagConstraints1.fill = GridBagConstraints.BOTH;
+			gridBagConstraints1.gridwidth = 2;
+			gridBagConstraints1.anchor = GridBagConstraints.NORTH;
+			gridBagConstraints1.gridy = 0;
+			jLabelFlagimage = new JLabel(new ImageIcon(
+					TranslationEditJPanel.class
+							.getResource("resource/flags.jpg")));
+			jContentPane = new JPanel();
+			jContentPane.setLayout(new GridBagLayout());
+			jContentPane.add(jLabelFlagimage, gridBagConstraints1);
+			jContentPane.add(getJPanel(), gridBagConstraints3);
+			jContentPane.add(getJPanel1(), gridBagConstraints11);
+		}
+		return jContentPane;
+	}
+
+	/**
+	 * This method initializes jPanel
+	 * 
+	 * @return javax.swing.JPanel
+	 */
+	private JPanel getJPanel() {
+		if (jPanel == null) {
+			final GridBagConstraints gridBagConstraints4 = new GridBagConstraints();
+			gridBagConstraints4.gridx = 0;
+			gridBagConstraints4.anchor = GridBagConstraints.EAST;
+			gridBagConstraints4.weightx = 1.0;
+			gridBagConstraints4.insets = new Insets(5, 5, 5, 5);
+			gridBagConstraints4.gridy = 0;
+			jPanel = new JPanel();
+			jPanel.setLayout(new GridBagLayout());
+			jPanel.add(getJButton(), gridBagConstraints4);
+		}
+		return jPanel;
+	}
+
+	/**
+	 * This method initializes jButton
+	 * 
+	 * @return javax.swing.JButton
+	 */
+	private JButton getJButton() {
+		if (jButton == null) {
+			jButton = new OkButton();
+			jButton.setEnabled(false);
+
+			jButton.addActionListener(new ActionListener() {
+
+				public void actionPerformed(ActionEvent e) {
+					dispose();
+				}
+
+			});
+		}
+		return jButton;
+	}
+
+	/**
+	 * This method initializes jPanel1
+	 * 
+	 * @return javax.swing.JPanel
+	 */
+	private JPanel getJPanel1() {
+		if (jPanel1 == null) {
+			final GridBagConstraints gridBagConstraints2 = new GridBagConstraints();
+			gridBagConstraints2.fill = GridBagConstraints.VERTICAL;
+			gridBagConstraints2.gridy = 0;
+			gridBagConstraints2.weightx = 1.0;
+			gridBagConstraints2.insets = new Insets(5, 5, 5, 5);
+			gridBagConstraints2.anchor = GridBagConstraints.WEST;
+			gridBagConstraints2.gridx = 1;
+			final GridBagConstraints gridBagConstraints = new GridBagConstraints();
+			gridBagConstraints.gridx = 0;
+			gridBagConstraints.insets = new Insets(0, 5, 0, 0);
+			gridBagConstraints.gridy = 0;
+			jLabel = new JLabel();
+			jLabel.setText("Select language: "); // i8n!?! Maybe replace with an
+													// icon of an index finger
+			jPanel1 = new JPanel();
+			jPanel1.setLayout(new GridBagLayout());
+			jPanel1.add(jLabel, gridBagConstraints);
+			jPanel1.add(getJComboBox(), gridBagConstraints2);
+		}
+		return jPanel1;
+	}
+
+	/**
+	 * This method initializes jComboBox
+	 * 
+	 * @return javax.swing.JComboBox
+	 */
+	private JComboBox getJComboBox() {
+		if (jComboBox == null) {
+			jComboBox = new JComboBox();
+
+			jComboBox.addMouseWheelListener(new MouseWheelListener() {
+				public void mouseWheelMoved(java.awt.event.MouseWheelEvent e) {
+
+					if ((e.getWheelRotation() < 0)) {
+						if (jComboBox.getSelectedIndex() < jComboBox
+								.getItemCount() - 1)
+							jComboBox.setSelectedIndex(jComboBox
+									.getSelectedIndex() + 1);
+					} else {
+						if (jComboBox.getSelectedIndex() > 0)
+							jComboBox.setSelectedIndex(jComboBox
+									.getSelectedIndex() - 1);
+					}
+				}
+			});
+
+			String[] langNames = new String[languages.size() + 1];
+			for (int i = 0; i < languages.size(); i++) {
+
+				Locale locale = I8NUtil.getLocaleFor(languages.get(i));
+
+				langNames[i] = locale.getDisplayLanguage(locale) + " / "
+						+ locale.getDisplayLanguage() + " / "
+						+ languages.get(i);
+			}
+			langNames[languages.size()] = "?";
+
+			jComboBox.setModel(new DefaultComboBoxModel(langNames));
+			jComboBox.setSelectedItem(langNames[languages.size()]);
+
+			jComboBox.addActionListener(new ActionListener() {
+
+				public void actionPerformed(final ActionEvent e) {
+					if (jComboBox.getSelectedIndex() == languages.size()) {
+						getJButton().setEnabled(false);
+						return;
+					}
+
+					String l = languages.get(jComboBox.getSelectedIndex());
+					try {
+						Translation.setActiveLang(l);
+
+						getJButton().setEnabled(true);
+					} catch (java.lang.IllegalArgumentException ee) {
+						LOGGER.warn("The language " + l + " is not valid", ee);
+						getJButton().setEnabled(false);
+					}
+
+				}
+
+			});
+		}
+		return jComboBox;
+	}
+
+} // @jve:decl-index=0:visual-constraint="0,0"

Modified: trunk/src/skrueger/i8n/Translation.java
===================================================================
--- trunk/src/skrueger/i8n/Translation.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/i8n/Translation.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,277 +1,306 @@
-package skrueger.i8n;
-
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Locale;
-
-import javax.swing.JComponent;
-import javax.swing.JTable;
-
-import org.apache.log4j.Logger;
-
-/**
- * Represents a {@link HashMap} of translations. toString() returns the
- * appropriate translation
- * 
- * @author @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
- *         Kr&uuml;ger</a>
- */
-
-public class Translation extends HashMap<String, String> {
-	public static final String LOCALECHANGE_PROPERTY = "localechange";
-	public static final String NO_TRANSLATION = "NO TRANSLATION";
-	public static final String DEFAULT_KEY = "default";
-	static final Logger log = Logger.getLogger(Translation.class);
-	static String activeLang = "fr";
-
-	static protected List<PropertyChangeListener> listeners = new ArrayList<PropertyChangeListener>();
-
-	static {
-
-		// TODO default aus Locale auslesen und mit möglichen vergleichen...
-		// mmm.. vor laden von atlasml immer DEFAULT_KEY, also hier nicht
-
-		// Get default locale
-		Locale locale = Locale.getDefault();
-		setActiveLang(locale.getLanguage());
-	}
-
-	@Override
-	/*
-	 * @comment To make a copy of a translation see methods toOneLine() and
-	 * fromOneLine()
-	 */
-	public Translation clone() {
-		return (Translation) super.clone();
-	}
-
-	/**
-	 * Get the two-letter language sting that is active
-	 */
-	public static String getActiveLang() {
-		return activeLang;
-	}
-
-	/**
-	 * Set up the {@link Translation}-system to use language. If a change is
-	 * performed, events are fired to listeners. Nothing is done if the new
-	 * language equals the old language. The system's default locale is changed.
-	 * 
-	 * @param newLang
-	 *            The ISO Code of the new active language
-	 */
-	public static void setActiveLang(String newLang) {
-		setActiveLang(newLang, true);
-	}
-
-	/**
-	 * Set up the {@link Translation}-system to use language. If a change is
-	 * performed, events are fired to listeners. Nothing is done if the new
-	 * language equals the old language.
-	 * 
-	 * @param newLang
-	 *            The ISO Code of the new active language
-	 * 
-	 * @param setDefaultLocale
-	 *            Shall the system's default locale be changed?
-	 */
-	public static void setActiveLang(String newLang, boolean setDefaultLocale) {
-		if (getActiveLang().equals(newLang)) {
-			return;
-		}
-
-		if (!I8NUtil.isValidISOLangCode(newLang)) {
-			throw new IllegalArgumentException("'" + newLang
-					+ "' is not a valid ISO language code.");
-		}
-
-		Locale newLocale = new Locale(newLang);
-		if (setDefaultLocale)
-			Locale.setDefault(newLocale);
-
-		/**
-		 * Setting default locale for Swing JComponents to work around bug
-		 * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4884480
-		 */
-		JComponent.setDefaultLocale(newLocale);
-
-		Translation.activeLang = newLang;
-
-		fireLocaleChangeEvents();
-
-		log.info("skrueger.i8n.Translation switched ActiveLang to " + newLang);
-	}
-
-	/**
-	 * Initializes a new {@link Translation} with a default translation if a
-	 * simple text is passed. If a "oneLine" text is parsed, it is interpreted.
-	 * Other translations may be added later - this is a HashMap<br/>
-	 * 
-	 * @param defaultTranslation
-	 * 
-	 * @see public Translation(List<String> languages, String
-	 *      defaultTranslation) {
-	 * 
-	 */
-	public Translation(String defaultTranslation) {
-
-		fromOneLine(defaultTranslation);
-
-	}
-
-	/**
-	 * Initializes a new {@link Translation}, an uses the given String to
-	 * initialize the {@link Translation} for all languages codes passed.
-	 * 
-	 * The translations can be changed later
-	 */
-	public Translation(List<String> languages, String defaultTranslation) {
-		// put(DEFAULT_KEY, defaultTranslation);
-		if (languages == null) {
-			put(DEFAULT_KEY, defaultTranslation);
-		} else
-			for (String code : languages) {
-				if (code.equals(getActiveLang())) {
-					put(code, defaultTranslation);
-				}
-			}
-	}
-
-	/**
-	 * Sometimes Translations are optional, like for keywords.
-	 */
-	public Translation() {
-	}
-
-	/**
-	 * Fills the {@link Translation} with the values coded into the String
-	 * Format of {@link String} is: "de{Baum}en{tree}"
-	 * <p>
-	 * <ul>
-	 * <li>If <code>oneLineCoded</code> is empty or null, NO TRANSLATION is set.
-	 * <li>If format can't be recognized, the {@link String} is interpreted as
-	 * the translation in the <code>{@value #DEFAULT_KEY}</code> language
-	 * 
-	 * @author Stefan Alfons Krüger
-	 */
-	public void fromOneLine(final String oneLineCoded) {
-		clear();
-		if ((oneLineCoded == null) || (oneLineCoded.equals(""))) {
-			put(DEFAULT_KEY, "");
-			return;
-		}
-
-		if (oneLineCoded.indexOf("}") == -1) {
-			// log.warn("The String '"+oneLineCoded+"' is not in oneLine coded => put(DEFAULT_KEY,oneLineCoded);");
-			put(DEFAULT_KEY, oneLineCoded);
-		}
-
-		String eatUp = oneLineCoded;
-		while (eatUp.indexOf("}") != -1) {
-			String substring = eatUp.substring(0, eatUp.indexOf("}"));
-
-			// log.debug("substring = "+substring);
-			String key = substring.substring(0, substring.indexOf("{"));
-			String value = substring.substring(substring.indexOf("{") + 1,
-					substring.length());
-			// log.debug("key="+key);
-			// log.debug("value="+value);
-			put(key, value);
-			eatUp = eatUp.substring(eatUp.indexOf("}") + 1);
-		}
-	}
-
-	/**
-	 * Exports the Translations to a String of the Format: "de{Baum}en{tree}"
-	 * 
-	 * @author Stefan Alfons Krüger
-	 */
-	public String toOneLine() {
-		return I8NUtil.toOneLine(this);
-	}
-
-	/**
-	 * Returns the right translation by using the {@link #activeLang} field. If
-	 * no translation is set, an ugly String {@link #NO_TRANSLATION} will re
-	 * returned. This might be changed for the final release. If the correct
-	 * language was not found, any entry in the {@link Translation}
-	 * {@link HashMap} will be returned, that contains more than an empty
-	 * string.
-	 */
-	@Override
-	public String toString() {
-		if (get(activeLang) != null) {
-			return get(activeLang);
-		}
-		// ****************************************************************************
-		// MS: The ISDSS needs the concept of the default lang!! So I took the
-		// following in again!!
-		// ****************************************************************************
-		// else return "";
-		// //****************************************************************************
-		// // The following is commented out.. the concept of the default lang
-		// seems to be bad....
-		// //****************************************************************************
-		// MS:
-		else {
-			if (get(DEFAULT_KEY) != null) {
-				// log.debug("default lang returned, cuz the translation to "+activeLang+" was not found. Schmeiss raus martin, wenn du das mit der default trans geklärt hast.");
-				return get(DEFAULT_KEY);
-			}
-
-			// log.debug("return first best <> '' ");
-			if (size() > 0)
-				for (String s : values()) {
-					if ((s != null) && (s.trim().length() > 0))
-						return s;
-				}
-		}
-//		log.warn("No translation found!");
-		return NO_TRANSLATION;
-	}
-
-	/**
-	 * Copy this {@link Translation} to another {@link Translation} e.g. for
-	 * editing
-	 * 
-	 * @return the destination {@link Translation}
-	 */
-	public Translation copy(Translation backup) {
-		if (backup == null)
-			throw new IllegalArgumentException(
-					"Target translation may not be null.");
-		for (String s : keySet()) {
-			backup.put(s, get(s));
-		}
-		return backup;
-	}
-
-	/**
-	 * {@link PropertyChangeListener} can be registered to be informed when the
-	 * {@link Locale} changed.
-	 * 
-	 * @param propertyChangeListener
-	 */
-	public static void addLocaleChangeListener(
-			PropertyChangeListener propertyChangeListener) {
-		listeners.add(propertyChangeListener);
-	}
-
-	/**
-	 * Informs all registered {@link PropertyChangeListener}s about a change of
-	 * the the {@link Locale}.
-	 */
-	public static void fireLocaleChangeEvents() {
-		PropertyChangeEvent pce = new PropertyChangeEvent(new Translation(
-				new ArrayList<String>(), "fakeSource"), LOCALECHANGE_PROPERTY,
-				null, getActiveLang());
-		for (PropertyChangeListener pcl : listeners) {
-			if (pcl != null)
-				pcl.propertyChange(pce);
-		}
-	}
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package skrueger.i8n;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+
+import javax.swing.JComponent;
+import javax.swing.JTable;
+
+import org.apache.log4j.Logger;
+
+/**
+ * Represents a {@link HashMap} of translations. toString() returns the
+ * appropriate translation
+ * 
+ * @author @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons
+ *         Kr&uuml;ger</a>
+ */
+
+public class Translation extends HashMap<String, String> {
+	public static final String LOCALECHANGE_PROPERTY = "localechange";
+	public static final String NO_TRANSLATION = "NO TRANSLATION";
+	public static final String DEFAULT_KEY = "default";
+	static final Logger log = Logger.getLogger(Translation.class);
+	static String activeLang = "fr";
+
+	static protected List<PropertyChangeListener> listeners = new ArrayList<PropertyChangeListener>();
+
+	static {
+
+		// TODO default aus Locale auslesen und mit möglichen vergleichen...
+		// mmm.. vor laden von atlasml immer DEFAULT_KEY, also hier nicht
+
+		// Get default locale
+		Locale locale = Locale.getDefault();
+		setActiveLang(locale.getLanguage());
+	}
+
+	@Override
+	/*
+	 * @comment To make a copy of a translation see methods toOneLine() and
+	 * fromOneLine()
+	 */
+	public Translation clone() {
+		return (Translation) super.clone();
+	}
+
+	/**
+	 * Get the two-letter language sting that is active
+	 */
+	public static String getActiveLang() {
+		return activeLang;
+	}
+
+	/**
+	 * Set up the {@link Translation}-system to use language. If a change is
+	 * performed, events are fired to listeners. Nothing is done if the new
+	 * language equals the old language. The system's default locale is changed.
+	 * 
+	 * @param newLang
+	 *            The ISO Code of the new active language
+	 */
+	public static void setActiveLang(String newLang) {
+		setActiveLang(newLang, true);
+	}
+
+	/**
+	 * Set up the {@link Translation}-system to use language. If a change is
+	 * performed, events are fired to listeners. Nothing is done if the new
+	 * language equals the old language.
+	 * 
+	 * @param newLang
+	 *            The ISO Code of the new active language
+	 * 
+	 * @param setDefaultLocale
+	 *            Shall the system's default locale be changed?
+	 */
+	public static void setActiveLang(String newLang, boolean setDefaultLocale) {
+		if (getActiveLang().equals(newLang)) {
+			return;
+		}
+
+		if (!I8NUtil.isValidISOLangCode(newLang)) {
+			throw new IllegalArgumentException("'" + newLang
+					+ "' is not a valid ISO language code.");
+		}
+
+		Locale newLocale = new Locale(newLang);
+		if (setDefaultLocale)
+			Locale.setDefault(newLocale);
+
+		/**
+		 * Setting default locale for Swing JComponents to work around bug
+		 * http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4884480
+		 */
+		JComponent.setDefaultLocale(newLocale);
+
+		Translation.activeLang = newLang;
+
+		fireLocaleChangeEvents();
+
+		log.info("skrueger.i8n.Translation switched ActiveLang to " + newLang);
+	}
+
+	/**
+	 * Initializes a new {@link Translation} with a default translation if a
+	 * simple text is passed. If a "oneLine" text is parsed, it is interpreted.
+	 * Other translations may be added later - this is a HashMap<br/>
+	 * 
+	 * @param defaultTranslation
+	 * 
+	 * @see public Translation(List<String> languages, String
+	 *      defaultTranslation) {
+	 * 
+	 */
+	public Translation(String defaultTranslation) {
+
+		fromOneLine(defaultTranslation);
+
+	}
+
+	/**
+	 * Initializes a new {@link Translation}, an uses the given String to
+	 * initialize the {@link Translation} for all languages codes passed.
+	 * 
+	 * The translations can be changed later
+	 */
+	public Translation(List<String> languages, String defaultTranslation) {
+		// put(DEFAULT_KEY, defaultTranslation);
+		if (languages == null) {
+			put(DEFAULT_KEY, defaultTranslation);
+		} else
+			for (String code : languages) {
+				if (code.equals(getActiveLang())) {
+					put(code, defaultTranslation);
+				}
+			}
+	}
+
+	/**
+	 * Sometimes Translations are optional, like for keywords.
+	 */
+	public Translation() {
+	}
+
+	/**
+	 * Fills the {@link Translation} with the values coded into the String
+	 * Format of {@link String} is: "de{Baum}en{tree}"
+	 * <p>
+	 * <ul>
+	 * <li>If <code>oneLineCoded</code> is empty or null, NO TRANSLATION is set.
+	 * <li>If format can't be recognized, the {@link String} is interpreted as
+	 * the translation in the <code>{@value #DEFAULT_KEY}</code> language
+	 * 
+	 * @author Stefan Alfons Krüger
+	 */
+	public void fromOneLine(final String oneLineCoded) {
+		clear();
+		if ((oneLineCoded == null) || (oneLineCoded.equals(""))) {
+			put(DEFAULT_KEY, "");
+			return;
+		}
+
+		if (oneLineCoded.indexOf("}") == -1) {
+			// log.warn("The String '"+oneLineCoded+"' is not in oneLine coded => put(DEFAULT_KEY,oneLineCoded);");
+			put(DEFAULT_KEY, oneLineCoded);
+		}
+
+		String eatUp = oneLineCoded;
+		while (eatUp.indexOf("}") != -1) {
+			String substring = eatUp.substring(0, eatUp.indexOf("}"));
+
+			// log.debug("substring = "+substring);
+			String key = substring.substring(0, substring.indexOf("{"));
+			String value = substring.substring(substring.indexOf("{") + 1,
+					substring.length());
+			// log.debug("key="+key);
+			// log.debug("value="+value);
+			put(key, value);
+			eatUp = eatUp.substring(eatUp.indexOf("}") + 1);
+		}
+	}
+
+	/**
+	 * Exports the Translations to a String of the Format: "de{Baum}en{tree}"
+	 * 
+	 * @author Stefan Alfons Krüger
+	 */
+	public String toOneLine() {
+		return I8NUtil.toOneLine(this);
+	}
+
+	/**
+	 * Returns the right translation by using the {@link #activeLang} field. If
+	 * no translation is set, an ugly String {@link #NO_TRANSLATION} will re
+	 * returned. This might be changed for the final release. If the correct
+	 * language was not found, any entry in the {@link Translation}
+	 * {@link HashMap} will be returned, that contains more than an empty
+	 * string.
+	 */
+	@Override
+	public String toString() {
+		if (get(activeLang) != null) {
+			return get(activeLang);
+		}
+		// ****************************************************************************
+		// MS: The ISDSS needs the concept of the default lang!! So I took the
+		// following in again!!
+		// ****************************************************************************
+		// else return "";
+		// //****************************************************************************
+		// // The following is commented out.. the concept of the default lang
+		// seems to be bad....
+		// //****************************************************************************
+		// MS:
+		else {
+			if (get(DEFAULT_KEY) != null) {
+				// log.debug("default lang returned, cuz the translation to "+activeLang+" was not found. Schmeiss raus martin, wenn du das mit der default trans geklärt hast.");
+				return get(DEFAULT_KEY);
+			}
+
+			// log.debug("return first best <> '' ");
+			if (size() > 0)
+				for (String s : values()) {
+					if ((s != null) && (s.trim().length() > 0))
+						return s;
+				}
+		}
+//		log.warn("No translation found!");
+		return NO_TRANSLATION;
+	}
+
+	/**
+	 * Copy this {@link Translation} to another {@link Translation} e.g. for
+	 * editing
+	 * 
+	 * @return the destination {@link Translation}
+	 */
+	public Translation copy(Translation backup) {
+		if (backup == null)
+			throw new IllegalArgumentException(
+					"Target translation may not be null.");
+		for (String s : keySet()) {
+			backup.put(s, get(s));
+		}
+		return backup;
+	}
+
+	/**
+	 * {@link PropertyChangeListener} can be registered to be informed when the
+	 * {@link Locale} changed.
+	 * 
+	 * @param propertyChangeListener
+	 */
+	public static void addLocaleChangeListener(
+			PropertyChangeListener propertyChangeListener) {
+		listeners.add(propertyChangeListener);
+	}
+
+	/**
+	 * Informs all registered {@link PropertyChangeListener}s about a change of
+	 * the the {@link Locale}.
+	 */
+	public static void fireLocaleChangeEvents() {
+		PropertyChangeEvent pce = new PropertyChangeEvent(new Translation(
+				new ArrayList<String>(), "fakeSource"), LOCALECHANGE_PROPERTY,
+				null, getActiveLang());
+		for (PropertyChangeListener pcl : listeners) {
+			if (pcl != null)
+				pcl.propertyChange(pce);
+		}
+	}
+
+}

Modified: trunk/src/skrueger/swing/CancelButton.java
===================================================================
--- trunk/src/skrueger/swing/CancelButton.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/swing/CancelButton.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,39 +1,68 @@
-package skrueger.swing;
-
-import java.awt.Dimension;
-
-import javax.swing.Action;
-import javax.swing.Icon;
-import javax.swing.ImageIcon;
-import javax.swing.JButton;
-/**
- * A Cancel {@link JButton} without text, but with an expressive {@link Icon}
- * stat symbolizes CANCEL
- * 
- * @author Stefan Alfons Krüger
- * 
- */
-public class CancelButton extends JButton {
-	public static final Icon ICON_CANCEL_SMALL 		= new ImageIcon( CancelButton.class.getResource("small/cancel.png") );
-
-	private static final Dimension DIMENSION = new Dimension(35,25);
-	
-	/**
-	 * Creates a {@link JButton} with an icon that symbolizes OK
-	 */
-	public CancelButton() {
-		super(ICON_CANCEL_SMALL);
-		setMaximumSize(DIMENSION);
-	}
-
-	/**
-	 * Creates a {@link JButton} with an icon that symbolizes OK
-	 */
-	public CancelButton(Action a) {
-		super(a);
-		setIcon(ICON_CANCEL_SMALL);
-		setMaximumSize(DIMENSION);
-	}
-
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package skrueger.swing;
+
+import java.awt.Dimension;
+
+import javax.swing.Action;
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+/**
+ * A Cancel {@link JButton} without text, but with an expressive {@link Icon}
+ * stat symbolizes CANCEL
+ * 
+ * @author Stefan Alfons Krüger
+ * 
+ */
+public class CancelButton extends JButton {
+	public static final Icon ICON_CANCEL_SMALL 		= new ImageIcon( CancelButton.class.getResource("small/cancel.png") );
+
+	private static final Dimension DIMENSION = new Dimension(35,25);
+	
+	/**
+	 * Creates a {@link JButton} with an icon that symbolizes OK
+	 */
+	public CancelButton() {
+		super(ICON_CANCEL_SMALL);
+		setMaximumSize(DIMENSION);
+	}
+
+	/**
+	 * Creates a {@link JButton} with an icon that symbolizes OK
+	 */
+	public CancelButton(Action a) {
+		super(a);
+		setIcon(ICON_CANCEL_SMALL);
+		setMaximumSize(DIMENSION);
+	}
+
+
+}

Modified: trunk/src/skrueger/swing/OkButton.java
===================================================================
--- trunk/src/skrueger/swing/OkButton.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/swing/OkButton.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,39 +1,68 @@
-package skrueger.swing;
-
-import java.awt.Dimension;
-
-import javax.swing.Action;
-import javax.swing.Icon;
-import javax.swing.ImageIcon;
-import javax.swing.JButton;
-
-/**
- * An Ok {@link JButton} without text, but with an expressive {@link Icon} that
- * symbolizes OK
- * 
- * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
- */
-public class OkButton extends JButton {
-
-	public static final Icon ICON_OK_SMALL = new ImageIcon(OkButton.class
-			.getResource("small/ok.png"));
-
-	private static final Dimension DIMENSION = new Dimension(35, 25);
-
-	/**
-	 * Creates a {@link JButton} with an icon that symbolizes OK
-	 */
-	public OkButton() {
-		super(ICON_OK_SMALL);
-		setMaximumSize(DIMENSION);
-	}
-
-	/**
-	 * Creates a {@link JButton} with an icon that symbolizes OK
-	 */
-	public OkButton(Action a) {
-		super(a);
-		setIcon(ICON_OK_SMALL);
-		setMaximumSize(DIMENSION);
-	}
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package skrueger.swing;
+
+import java.awt.Dimension;
+
+import javax.swing.Action;
+import javax.swing.Icon;
+import javax.swing.ImageIcon;
+import javax.swing.JButton;
+
+/**
+ * An Ok {@link JButton} without text, but with an expressive {@link Icon} that
+ * symbolizes OK
+ * 
+ * @author <a href="mailto:skpublic at wikisquare.de">Stefan Alfons Kr&uuml;ger</a>
+ */
+public class OkButton extends JButton {
+
+	public static final Icon ICON_OK_SMALL = new ImageIcon(OkButton.class
+			.getResource("small/ok.png"));
+
+	private static final Dimension DIMENSION = new Dimension(35, 25);
+
+	/**
+	 * Creates a {@link JButton} with an icon that symbolizes OK
+	 */
+	public OkButton() {
+		super(ICON_OK_SMALL);
+		setMaximumSize(DIMENSION);
+	}
+
+	/**
+	 * Creates a {@link JButton} with an icon that symbolizes OK
+	 */
+	public OkButton(Action a) {
+		super(a);
+		setIcon(ICON_OK_SMALL);
+		setMaximumSize(DIMENSION);
+	}
+}

Modified: trunk/src/skrueger/swing/TranslationAskJDialog.java
===================================================================
--- trunk/src/skrueger/swing/TranslationAskJDialog.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/swing/TranslationAskJDialog.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,286 +1,315 @@
-package skrueger.swing;
-
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.FlowLayout;
-import java.awt.Window;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.KeyEvent;
-import java.awt.event.WindowAdapter;
-import java.awt.event.WindowEvent;
-import java.util.Locale;
-
-import javax.swing.AbstractAction;
-import javax.swing.Action;
-import javax.swing.BorderFactory;
-import javax.swing.Box;
-import javax.swing.JButton;
-import javax.swing.JComponent;
-import javax.swing.JDialog;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JRootPane;
-import javax.swing.KeyStroke;
-
-import schmitzm.geotools.styling.StylingUtil;
-import schmitzm.lang.LangUtil;
-import schmitzm.lang.ResourceProvider;
-import schmitzm.swing.SwingUtil;
-import skrueger.i8n.Translation;
-
-public class TranslationAskJDialog extends JDialog {
-
-	private String[] backup = new String[50]; // Maximum 50 languages ;-)
-	private OkButton okButton;
-	private CancelButton cancelButton;
-
-	public static final String PROPERTY_CANCEL_AND_CLOSE = "CANCEL";
-	public static final String PROPERTY_APPLY_AND_CLOSE = "APPLY";
-
-	private JComponent[] translationEditJPanelsOrJustComponents;
-
-	private boolean hasBeenCanceled;
-
-	private JButton[] optionalButtons;
-
-	/**
-	 * Since the registerKeyboardAction() method is part of the JComponent class
-	 * definition, you must define the Escape keystroke and register the
-	 * keyboard action with a JComponent, not with a JDialog. The JRootPane for
-	 * the JDialog serves as an excellent choice to associate the registration,
-	 * as this will always be visible. If you override the protected
-	 * createRootPane() method of JDialog, you can return your custom JRootPane
-	 * with the keystroke enabled:
-	 */
-	@Override
-	protected JRootPane createRootPane() {
-		KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
-		JRootPane rootPane = new JRootPane();
-		rootPane.registerKeyboardAction(new ActionListener() {
-
-			public void actionPerformed(ActionEvent e) {
-				cancel();
-			}
-
-		}, stroke, JComponent.WHEN_IN_FOCUSED_WINDOW);
-
-		return rootPane;
-	}
-
-	/**
-	 * The {@link TranslationAskJDialog} fills its content pane with an
-	 * arbitrary number of components. If these {@link Component}s are
-	 * {@link TranslationEditJPanel}s, the {@link JDialog} manages to backup the
-	 * values and restore them if the dialog is canceled. Other
-	 * {@link JComponent}s are just displayed.<br/>
-	 * This class handles the cancel button itself. You may still want to listen
-	 * to PROPERTY_APPLY_AND_CLOSE events. This dialog is modal. The dialog has
-	 * to be set visible afterwards.<br/>
-	 * 
-	 * @param owner
-	 *            A component of the GUI that this dialog is related to. If no
-	 *            {@link Window} is passed, SwingUtil.getParentWindow(owner) is
-	 *            called.
-	 */
-	public TranslationAskJDialog(Component owner,
-			final JComponent... translationEditJPanels) {
-		super(SwingUtil.getParentWindow(owner));
-		setComponents(translationEditJPanels);
-	}
-
-	/**
-	 * The {@link TranslationAskJDialog} fills its content pane with an
-	 * arbitrary number of components. If these {@link Component}s are
-	 * {@link TranslationEditJPanel}s, the {@link JDialog} manages to backup the
-	 * values and restore them if the dialog is canceled. Other
-	 * {@link JComponent}s are just displayed.<br/>
-	 * This class handles the cancel button itself. You may still want to listen
-	 * to PROPERTY_APPLY_AND_CLOSE events. This dialog is modal. The dialog has
-	 * to be set visible afterwards.<br/>
-	 * Using this constructor, you have to call setComponents afterwards.
-	 */
-	public TranslationAskJDialog(Component owner) {
-		this(owner, new JComponent[] {});
-	}
-
-	/**
-	 * The {@link TranslationAskJDialog} fills its content pane with an
-	 * arbitrary number of components. If these {@link Component}s are
-	 * {@link TranslationEditJPanel}s, the {@link JDialog} manages to backup the
-	 * values and restore them if the dialog is canceled. Other
-	 * {@link JComponent}s are just displayed.
-	 * 
-	 * @param translationEditJPanels
-	 *            Arbitrary list of {@link JComponent}s and
-	 *            {@link TranslationEditJPanel}s.
-	 */
-	public void setComponents(final JComponent... translationEditJPanels) {
-		this.translationEditJPanelsOrJustComponents = translationEditJPanels;
-
-		// Remember backups for all the TranslationEditJPanel
-		int count = 0;
-		for (JComponent component : translationEditJPanelsOrJustComponents) {
-			if (component instanceof TranslationEditJPanel) {
-				TranslationEditJPanel tep = (TranslationEditJPanel) component;
-				Translation orig = tep.getTranslation();
-
-				// We don't want to overwrite the Translation object on
-				// restore(). We just want to change its value.
-				backup[count++] = orig.toOneLine();
-			}
-		}
-
-		init();
-	}
-
-	private void init() {
-		setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
-		addWindowListener(new WindowAdapter() {
-
-			public void windowClosing(WindowEvent e) {
-				cancel();
-			}
-
-		});
-		SwingUtil.centerFrameOnScreen(this);
-		Box box = Box.createVerticalBox();
-		for (JComponent panel : translationEditJPanelsOrJustComponents) {
-			panel.setAlignmentX(java.awt.Component.LEFT_ALIGNMENT);
-			panel.setBorder( BorderFactory.createEmptyBorder(5, 6, 5, 6));
-			box.add(panel);
-			
-		}
-		JPanel cp = new JPanel(new BorderLayout());
-		cp.add(box, BorderLayout.WEST);
-		cp.add(getButtons(), BorderLayout.SOUTH);
-		setContentPane(cp);
-		
-		setTitle(SwingUtil.R("TranslationAskJDialog.Title")); 
-		setModal(true);
-		pack();
-	}
-
-	public void setButtons(JButton... optionalButtons) {
-		this.optionalButtons = optionalButtons;
-		init();
-	}
-
-	protected void cancel() {
-		firePropertyChange(PROPERTY_CANCEL_AND_CLOSE, null, null);
-		restore();
-		setVisible(false);
-		dispose();
-	}
-
-	protected void restore() {
-		int count = 0;
-		for (JComponent component : translationEditJPanelsOrJustComponents) {
-			if (component instanceof TranslationEditJPanel) {
-				TranslationEditJPanel tep = (TranslationEditJPanel) component;
-				tep.getTranslation().fromOneLine(backup[count++]);
-			}
-		}
-	}
-
-	private JComponent getButtons() {
-		JPanel jPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
-
-		if (optionalButtons != null)
-			for (JButton b : optionalButtons) {
-				jPanel.add(b);
-			}
-
-		if (okButton == null) {
-			okButton = new OkButton(new AbstractAction() {
-				{
-					// Set a mnemonic character. In most look and feels, this
-					// causes the
-					// specified character to be underlined This indicates that
-					// if the component
-					// using this action has the focus and In some look and
-					// feels, this causes
-					// the specified character in the label to be underlined and
-					putValue(Action.MNEMONIC_KEY, new Integer(
-							java.awt.event.KeyEvent.VK_E));
-
-					// Set tool tip text
-					putValue(Action.SHORT_DESCRIPTION,
-							"Accept the changes made to the translation.");
-
-				}
-
-				public void actionPerformed(ActionEvent evt) {
-					TranslationAskJDialog.this.firePropertyChange(
-							PROPERTY_APPLY_AND_CLOSE, null, null);
-
-					if (!checkValidInputs())
-						return;
-
-					setVisible(false);
-					dispose();
-				}
-
-			});
-
-		}
-		jPanel.add(okButton);
-
-		if (cancelButton == null) {
-			cancelButton = new CancelButton(new AbstractAction("") {
-				public void actionPerformed(ActionEvent evt) {
-					restore();
-					TranslationAskJDialog.this.firePropertyChange(
-							PROPERTY_CANCEL_AND_CLOSE, null, null);
-					setVisible(false);
-					setCancelled(true);
-					dispose();
-				}
-			});
-		}
-		jPanel.add(cancelButton);
-
-		return jPanel;
-	}
-
-	/**
-	 * @return <code>true</code> if none of the translations contains illegal
-	 *         characters.
-	 */
-	protected boolean checkValidInputs() {
-
-		for (JComponent component : translationEditJPanelsOrJustComponents) {
-			if (component instanceof TranslationEditJPanel) {
-				TranslationEditJPanel tep = (TranslationEditJPanel) component;
-
-				for (String l : tep.getTranslation().values()) {
-					if (l.contains("{") || l.contains("}")) {
-						JOptionPane
-								.showMessageDialog(
-										this,
-										SwingUtil.R("TranslationAskJDialog.ErrorMsg.InvalidCharacterInTranslation"));
-						return false;
-					}
-				}
-
-			}
-		}
-
-		return true;
-	}
-
-	private void setCancelled(boolean hasBeenCanceled) {
-		this.hasBeenCanceled = hasBeenCanceled;
-	}
-
-	/**
-	 * After the modal dialog has been closed, this allows to find out, whether
-	 * the dialog has been canceled.
-	 * 
-	 * @return <code>true</code> if the {@link JDialog} has been canceled.
-	 */
-	public boolean isCancelled() {
-		return hasBeenCanceled;
-	}
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package skrueger.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.FlowLayout;
+import java.awt.Window;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
+import java.util.Locale;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.BorderFactory;
+import javax.swing.Box;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JDialog;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JRootPane;
+import javax.swing.KeyStroke;
+
+import schmitzm.geotools.styling.StylingUtil;
+import schmitzm.lang.LangUtil;
+import schmitzm.lang.ResourceProvider;
+import schmitzm.swing.SwingUtil;
+import skrueger.i8n.Translation;
+
+public class TranslationAskJDialog extends JDialog {
+
+	private String[] backup = new String[50]; // Maximum 50 languages ;-)
+	private OkButton okButton;
+	private CancelButton cancelButton;
+
+	public static final String PROPERTY_CANCEL_AND_CLOSE = "CANCEL";
+	public static final String PROPERTY_APPLY_AND_CLOSE = "APPLY";
+
+	private JComponent[] translationEditJPanelsOrJustComponents;
+
+	private boolean hasBeenCanceled;
+
+	private JButton[] optionalButtons;
+
+	/**
+	 * Since the registerKeyboardAction() method is part of the JComponent class
+	 * definition, you must define the Escape keystroke and register the
+	 * keyboard action with a JComponent, not with a JDialog. The JRootPane for
+	 * the JDialog serves as an excellent choice to associate the registration,
+	 * as this will always be visible. If you override the protected
+	 * createRootPane() method of JDialog, you can return your custom JRootPane
+	 * with the keystroke enabled:
+	 */
+	@Override
+	protected JRootPane createRootPane() {
+		KeyStroke stroke = KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0);
+		JRootPane rootPane = new JRootPane();
+		rootPane.registerKeyboardAction(new ActionListener() {
+
+			public void actionPerformed(ActionEvent e) {
+				cancel();
+			}
+
+		}, stroke, JComponent.WHEN_IN_FOCUSED_WINDOW);
+
+		return rootPane;
+	}
+
+	/**
+	 * The {@link TranslationAskJDialog} fills its content pane with an
+	 * arbitrary number of components. If these {@link Component}s are
+	 * {@link TranslationEditJPanel}s, the {@link JDialog} manages to backup the
+	 * values and restore them if the dialog is canceled. Other
+	 * {@link JComponent}s are just displayed.<br/>
+	 * This class handles the cancel button itself. You may still want to listen
+	 * to PROPERTY_APPLY_AND_CLOSE events. This dialog is modal. The dialog has
+	 * to be set visible afterwards.<br/>
+	 * 
+	 * @param owner
+	 *            A component of the GUI that this dialog is related to. If no
+	 *            {@link Window} is passed, SwingUtil.getParentWindow(owner) is
+	 *            called.
+	 */
+	public TranslationAskJDialog(Component owner,
+			final JComponent... translationEditJPanels) {
+		super(SwingUtil.getParentWindow(owner));
+		setComponents(translationEditJPanels);
+	}
+
+	/**
+	 * The {@link TranslationAskJDialog} fills its content pane with an
+	 * arbitrary number of components. If these {@link Component}s are
+	 * {@link TranslationEditJPanel}s, the {@link JDialog} manages to backup the
+	 * values and restore them if the dialog is canceled. Other
+	 * {@link JComponent}s are just displayed.<br/>
+	 * This class handles the cancel button itself. You may still want to listen
+	 * to PROPERTY_APPLY_AND_CLOSE events. This dialog is modal. The dialog has
+	 * to be set visible afterwards.<br/>
+	 * Using this constructor, you have to call setComponents afterwards.
+	 */
+	public TranslationAskJDialog(Component owner) {
+		this(owner, new JComponent[] {});
+	}
+
+	/**
+	 * The {@link TranslationAskJDialog} fills its content pane with an
+	 * arbitrary number of components. If these {@link Component}s are
+	 * {@link TranslationEditJPanel}s, the {@link JDialog} manages to backup the
+	 * values and restore them if the dialog is canceled. Other
+	 * {@link JComponent}s are just displayed.
+	 * 
+	 * @param translationEditJPanels
+	 *            Arbitrary list of {@link JComponent}s and
+	 *            {@link TranslationEditJPanel}s.
+	 */
+	public void setComponents(final JComponent... translationEditJPanels) {
+		this.translationEditJPanelsOrJustComponents = translationEditJPanels;
+
+		// Remember backups for all the TranslationEditJPanel
+		int count = 0;
+		for (JComponent component : translationEditJPanelsOrJustComponents) {
+			if (component instanceof TranslationEditJPanel) {
+				TranslationEditJPanel tep = (TranslationEditJPanel) component;
+				Translation orig = tep.getTranslation();
+
+				// We don't want to overwrite the Translation object on
+				// restore(). We just want to change its value.
+				backup[count++] = orig.toOneLine();
+			}
+		}
+
+		init();
+	}
+
+	private void init() {
+		setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
+		addWindowListener(new WindowAdapter() {
+
+			public void windowClosing(WindowEvent e) {
+				cancel();
+			}
+
+		});
+		SwingUtil.centerFrameOnScreen(this);
+		Box box = Box.createVerticalBox();
+		for (JComponent panel : translationEditJPanelsOrJustComponents) {
+			panel.setAlignmentX(java.awt.Component.LEFT_ALIGNMENT);
+			panel.setBorder( BorderFactory.createEmptyBorder(5, 6, 5, 6));
+			box.add(panel);
+			
+		}
+		JPanel cp = new JPanel(new BorderLayout());
+		cp.add(box, BorderLayout.WEST);
+		cp.add(getButtons(), BorderLayout.SOUTH);
+		setContentPane(cp);
+		
+		setTitle(SwingUtil.R("TranslationAskJDialog.Title")); 
+		setModal(true);
+		pack();
+	}
+
+	public void setButtons(JButton... optionalButtons) {
+		this.optionalButtons = optionalButtons;
+		init();
+	}
+
+	protected void cancel() {
+		firePropertyChange(PROPERTY_CANCEL_AND_CLOSE, null, null);
+		restore();
+		setVisible(false);
+		dispose();
+	}
+
+	protected void restore() {
+		int count = 0;
+		for (JComponent component : translationEditJPanelsOrJustComponents) {
+			if (component instanceof TranslationEditJPanel) {
+				TranslationEditJPanel tep = (TranslationEditJPanel) component;
+				tep.getTranslation().fromOneLine(backup[count++]);
+			}
+		}
+	}
+
+	private JComponent getButtons() {
+		JPanel jPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
+
+		if (optionalButtons != null)
+			for (JButton b : optionalButtons) {
+				jPanel.add(b);
+			}
+
+		if (okButton == null) {
+			okButton = new OkButton(new AbstractAction() {
+				{
+					// Set a mnemonic character. In most look and feels, this
+					// causes the
+					// specified character to be underlined This indicates that
+					// if the component
+					// using this action has the focus and In some look and
+					// feels, this causes
+					// the specified character in the label to be underlined and
+					putValue(Action.MNEMONIC_KEY, new Integer(
+							java.awt.event.KeyEvent.VK_E));
+
+					// Set tool tip text
+					putValue(Action.SHORT_DESCRIPTION,
+							"Accept the changes made to the translation.");
+
+				}
+
+				public void actionPerformed(ActionEvent evt) {
+					TranslationAskJDialog.this.firePropertyChange(
+							PROPERTY_APPLY_AND_CLOSE, null, null);
+
+					if (!checkValidInputs())
+						return;
+
+					setVisible(false);
+					dispose();
+				}
+
+			});
+
+		}
+		jPanel.add(okButton);
+
+		if (cancelButton == null) {
+			cancelButton = new CancelButton(new AbstractAction("") {
+				public void actionPerformed(ActionEvent evt) {
+					restore();
+					TranslationAskJDialog.this.firePropertyChange(
+							PROPERTY_CANCEL_AND_CLOSE, null, null);
+					setVisible(false);
+					setCancelled(true);
+					dispose();
+				}
+			});
+		}
+		jPanel.add(cancelButton);
+
+		return jPanel;
+	}
+
+	/**
+	 * @return <code>true</code> if none of the translations contains illegal
+	 *         characters.
+	 */
+	protected boolean checkValidInputs() {
+
+		for (JComponent component : translationEditJPanelsOrJustComponents) {
+			if (component instanceof TranslationEditJPanel) {
+				TranslationEditJPanel tep = (TranslationEditJPanel) component;
+
+				for (String l : tep.getTranslation().values()) {
+					if (l.contains("{") || l.contains("}")) {
+						JOptionPane
+								.showMessageDialog(
+										this,
+										SwingUtil.R("TranslationAskJDialog.ErrorMsg.InvalidCharacterInTranslation"));
+						return false;
+					}
+				}
+
+			}
+		}
+
+		return true;
+	}
+
+	private void setCancelled(boolean hasBeenCanceled) {
+		this.hasBeenCanceled = hasBeenCanceled;
+	}
+
+	/**
+	 * After the modal dialog has been closed, this allows to find out, whether
+	 * the dialog has been canceled.
+	 * 
+	 * @return <code>true</code> if the {@link JDialog} has been canceled.
+	 */
+	public boolean isCancelled() {
+		return hasBeenCanceled;
+	}
+
+}

Modified: trunk/src/skrueger/swing/TranslationEditJPanel.java
===================================================================
--- trunk/src/skrueger/swing/TranslationEditJPanel.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/swing/TranslationEditJPanel.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,150 +1,179 @@
-package skrueger.swing;
-
-import java.awt.BorderLayout;
-import java.awt.Container;
-import java.awt.Dimension;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.awt.event.KeyEvent;
-import java.awt.event.KeyListener;
-import java.beans.PropertyChangeListener;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-
-import javax.swing.BorderFactory;
-import javax.swing.JLabel;
-import javax.swing.JPanel;
-import javax.swing.JTextField;
-import javax.swing.SpringLayout;
-import javax.swing.SwingConstants;
-
-import org.apache.log4j.Logger;
-
-import schmitzm.swing.SpringUtilities;
-import skrueger.i8n.Translation;
-
-/**
- * A {@link JPanel} that asks the user for the translations of a String in
- * several languages. Use {@link TranslationAskJDialog} to display.<br/>
- * The class does not implement any backup/clong strategies. The
- * {@link Translation} object is manipulated directly.<br/>
- * {@link TranslationEditJPanel}s. {@link TranslationAskJDialog} implements a
- * transparent Apply/Cancel logic.
- * 
- * @author Stefan Alfons Krüger
- */
-public class TranslationEditJPanel extends JPanel  {
-	static final protected Logger LOGGER = Logger
-			.getLogger(TranslationEditJPanel.class);
-
-	private final List<String> languages;
-	private JPanel translationGrid;
-	private Translation trans;
-
-	/**
-	 * Remembers all {@link JTextField} that have been created.
-	 */
-	private Set<JTextField> langTextFields = new HashSet<JTextField>();
-
-	/**
-	 * Creates a {@link JPanel} that asks the user for the translation of a
-	 * String in several languages
-	 */
-	public TranslationEditJPanel(Translation trans, List<String> languages_) {
-		this(null, trans, languages_);
-	}
-
-	/**
-	 * Creates a {@link JPanel} that asks the user for the translation of a
-	 * String in several languages and additionally puts a {@link JLabel} with a
-	 * question at the {@link JPanel}'s first row.
-	 */
-	public TranslationEditJPanel(String question, Translation trans,
-			List<String> languages_) {
-		super(new BorderLayout());
-
-		if (trans == null)
-			trans = new Translation();
-
-		this.trans = trans;
-		this.languages = languages_;
-
-		add(getTranslationGrid(), BorderLayout.CENTER);
-
-		if (question != null) {
-			JLabel questionLable = new JLabel(question);
-			questionLable
-					.setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6));
-			add(questionLable, BorderLayout.NORTH);
-		}
-	}
-
-	private JPanel getTranslationGrid() {
-		if (translationGrid == null) {
-			translationGrid = new JPanel(new SpringLayout());
-
-			for (String langId : languages) {
-
-				// language code : entry field for translation
-				JLabel langDesc = new JLabel(langId.toUpperCase() + " :"); // i8n
-				langDesc.setHorizontalAlignment(SwingConstants.RIGHT);
-				langDesc.setVerticalAlignment(SwingConstants.NORTH);
-
-				TranslationJTextField langTextField = new TranslationJTextField(
-						trans, langId);
-				// Setting a size
-				langTextField.setPreferredSize(new Dimension(360, 22));
-				langDesc.setLabelFor(langTextField);
-				translationGrid.add(langDesc);
-				translationGrid.add(langTextField);
-				
-				langTextFields .add(langTextField);
-			}
-
-			// Lay out the panel.
-			SpringUtilities.makeCompactGrid(translationGrid, languages.size(), // rows,
-					2, // cols
-					6, 6, // initX, initY
-					6, 6); // xPad, yPad
-
-		}
-		return translationGrid;
-	}
-
-	/**
-	 * @return The {@link Translation} that this {@link TranslationEditJPanel}
-	 *         deals with.
-	 */
-	public Translation getTranslation() {
-		return trans;
-	}
-
-	public void addActionListener(final ActionListener actionListener) {
-		for (final JTextField langTextField : langTextFields){
-			langTextField.addKeyListener( new KeyListener(){
-
-				@Override
-				public void keyPressed(KeyEvent e) {
-				}
-
-				@Override
-				public void keyReleased(KeyEvent e) {
-				}
-
-				@Override
-				public void keyTyped(KeyEvent e) {
-					actionListener.actionPerformed(new ActionEvent(TranslationEditJPanel.this, 0, ""));
-				}
-				
-			});
-		}
-	}
-
-	public void removeActionListener(ActionListener actionListener) {
-		for (JTextField langTextField : langTextFields){
-			langTextField.removeActionListener(actionListener);
-		}
-	}
-
-}
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
+package skrueger.swing;
+
+import java.awt.BorderLayout;
+import java.awt.Container;
+import java.awt.Dimension;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyEvent;
+import java.awt.event.KeyListener;
+import java.beans.PropertyChangeListener;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.swing.BorderFactory;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+import javax.swing.SpringLayout;
+import javax.swing.SwingConstants;
+
+import org.apache.log4j.Logger;
+
+import schmitzm.swing.SpringUtilities;
+import skrueger.i8n.Translation;
+
+/**
+ * A {@link JPanel} that asks the user for the translations of a String in
+ * several languages. Use {@link TranslationAskJDialog} to display.<br/>
+ * The class does not implement any backup/clong strategies. The
+ * {@link Translation} object is manipulated directly.<br/>
+ * {@link TranslationEditJPanel}s. {@link TranslationAskJDialog} implements a
+ * transparent Apply/Cancel logic.
+ * 
+ * @author Stefan Alfons Krüger
+ */
+public class TranslationEditJPanel extends JPanel  {
+	static final protected Logger LOGGER = Logger
+			.getLogger(TranslationEditJPanel.class);
+
+	private final List<String> languages;
+	private JPanel translationGrid;
+	private Translation trans;
+
+	/**
+	 * Remembers all {@link JTextField} that have been created.
+	 */
+	private Set<JTextField> langTextFields = new HashSet<JTextField>();
+
+	/**
+	 * Creates a {@link JPanel} that asks the user for the translation of a
+	 * String in several languages
+	 */
+	public TranslationEditJPanel(Translation trans, List<String> languages_) {
+		this(null, trans, languages_);
+	}
+
+	/**
+	 * Creates a {@link JPanel} that asks the user for the translation of a
+	 * String in several languages and additionally puts a {@link JLabel} with a
+	 * question at the {@link JPanel}'s first row.
+	 */
+	public TranslationEditJPanel(String question, Translation trans,
+			List<String> languages_) {
+		super(new BorderLayout());
+
+		if (trans == null)
+			trans = new Translation();
+
+		this.trans = trans;
+		this.languages = languages_;
+
+		add(getTranslationGrid(), BorderLayout.CENTER);
+
+		if (question != null) {
+			JLabel questionLable = new JLabel(question);
+			questionLable
+					.setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6));
+			add(questionLable, BorderLayout.NORTH);
+		}
+	}
+
+	private JPanel getTranslationGrid() {
+		if (translationGrid == null) {
+			translationGrid = new JPanel(new SpringLayout());
+
+			for (String langId : languages) {
+
+				// language code : entry field for translation
+				JLabel langDesc = new JLabel(langId.toUpperCase() + " :"); // i8n
+				langDesc.setHorizontalAlignment(SwingConstants.RIGHT);
+				langDesc.setVerticalAlignment(SwingConstants.NORTH);
+
+				TranslationJTextField langTextField = new TranslationJTextField(
+						trans, langId);
+				// Setting a size
+				langTextField.setPreferredSize(new Dimension(360, 22));
+				langDesc.setLabelFor(langTextField);
+				translationGrid.add(langDesc);
+				translationGrid.add(langTextField);
+				
+				langTextFields .add(langTextField);
+			}
+
+			// Lay out the panel.
+			SpringUtilities.makeCompactGrid(translationGrid, languages.size(), // rows,
+					2, // cols
+					6, 6, // initX, initY
+					6, 6); // xPad, yPad
+
+		}
+		return translationGrid;
+	}
+
+	/**
+	 * @return The {@link Translation} that this {@link TranslationEditJPanel}
+	 *         deals with.
+	 */
+	public Translation getTranslation() {
+		return trans;
+	}
+
+	public void addActionListener(final ActionListener actionListener) {
+		for (final JTextField langTextField : langTextFields){
+			langTextField.addKeyListener( new KeyListener(){
+
+				@Override
+				public void keyPressed(KeyEvent e) {
+				}
+
+				@Override
+				public void keyReleased(KeyEvent e) {
+				}
+
+				@Override
+				public void keyTyped(KeyEvent e) {
+					actionListener.actionPerformed(new ActionEvent(TranslationEditJPanel.this, 0, ""));
+				}
+				
+			});
+		}
+	}
+
+	public void removeActionListener(ActionListener actionListener) {
+		for (JTextField langTextField : langTextFields){
+			langTextField.removeActionListener(actionListener);
+		}
+	}
+
+}

Modified: trunk/src/skrueger/swing/TranslationJTextField.java
===================================================================
--- trunk/src/skrueger/swing/TranslationJTextField.java	2009-07-28 12:40:08 UTC (rev 243)
+++ trunk/src/skrueger/swing/TranslationJTextField.java	2009-07-29 09:33:33 UTC (rev 244)
@@ -1,3 +1,32 @@
+/*******************************************************************************
+ * Copyright (c) 2009 Martin O. J. Schmitz.
+ * 
+ * This file is part of the SCHMITZM library - a collection of utility 
+ * classes based on Java 1.6, focussing (not only) on Java Swing 
+ * and the Geotools library.
+ * 
+ * The SCHMITZM project is hosted at:
+ * http://wald.intevation.org/projects/schmitzm/
+ * 
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3
+ * of the License, or (at your option) any later version.
+ * 
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU Lesser General Public License (license.txt)
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ * or try this link: http://www.gnu.org/licenses/lgpl.html
+ * 
+ * Contributors:
+ *     Martin O. J. Schmitz - initial API and implementation
+ *     Stefan A. Krüger - additional utility classes
+ ******************************************************************************/
 package skrueger.swing;
 
 import java.awt.Color;



More information about the Schmitzm-commits mailing list