/[schmitzm]/trunk/src/skrueger/geotools/StyledLayerUtil.java
ViewVC logotype

Diff of /trunk/src/skrueger/geotools/StyledLayerUtil.java

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

trunk/src/skrueger/geotools/StyledMapUtil.java revision 127 by mojays, Sat May 30 14:29:58 2009 UTC branches/1.0-gt2-2.6/src/skrueger/geotools/StyledLayerUtil.java revision 397 by alfonx, Mon Sep 14 11:40:17 2009 UTC
# Line 1  Line 1 
1  package skrueger.geotools;  /*******************************************************************************
2     * Copyright (c) 2009 Martin O. J. Schmitz.
3  import java.io.File;   *
4  import java.io.FileNotFoundException;   * This file is part of the SCHMITZM library - a collection of utility
5  import java.io.FileWriter;   * classes based on Java 1.6, focusing (not only) on Java Swing
6  import java.net.URL;   * and the Geotools library.
7  import java.text.DecimalFormat;   *
8  import java.util.HashMap;   * The SCHMITZM project is hosted at:
9  import java.util.List;   * http://wald.intevation.org/projects/schmitzm/
10  import java.util.Map;   *
11  import java.util.SortedMap;   * This program is free software; you can redistribute it and/or
12  import java.util.TreeMap;   * modify it under the terms of the GNU Lesser General Public License
13     * as published by the Free Software Foundation; either version 3
14  import org.apache.log4j.Logger;   * of the License, or (at your option) any later version.
15  import org.geotools.coverage.grid.GridCoverage2D;   *
16  import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader;   * This program is distributed in the hope that it will be useful,
17  import org.geotools.feature.FeatureCollection;   * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  import org.geotools.map.DefaultMapLayer;   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  import org.geotools.map.MapLayer;   * GNU General Public License for more details.
20  import org.geotools.styling.ColorMap;   *
21  import org.geotools.styling.ColorMapEntry;   * You should have received a copy of the GNU Lesser General Public License (license.txt)
22  import org.geotools.styling.RasterSymbolizer;   * along with this program; if not, write to the Free Software
23  import org.geotools.styling.Style;   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
24  import org.jdom.Document;   * or try this link: http://www.gnu.org/licenses/lgpl.html
25  import org.jdom.Element;   *
26  import org.jdom.input.SAXBuilder;   * Contributors:
27  import org.jdom.output.XMLOutputter;   *     Martin O. J. Schmitz - initial API and implementation
28     *     Stefan A. Krüger - additional utility classes
29  import schmitzm.geotools.styling.StylingUtil;   ******************************************************************************/
30  import schmitzm.io.IOUtil;  package skrueger.geotools;
31  import schmitzm.lang.LangUtil;  
32  import schmitzm.swing.SwingUtil;  import java.awt.Color;
33  import skrueger.AttributeMetaData;  import java.awt.Dimension;
34  import skrueger.RasterLegendData;  import java.awt.Graphics;
35  import skrueger.i8n.Translation;  import java.awt.image.BufferedImage;
36    import java.io.File;
37  /**  import java.io.FileNotFoundException;
38   * This class provides static helper methods for dealing with  import java.io.FileWriter;
39   * {@link StyledMapInterface} stuff.  import java.net.URL;
40   * @author <a href="mailto:[email protected]">Martin Schmitz</a> (University of Bonn/Germany)  import java.text.DecimalFormat;
41   * @version 1.0  import java.util.HashMap;
42   */  import java.util.List;
43  public class StyledMapUtil {  import java.util.Map;
44    private static final Logger LOGGER = Logger.getLogger(StyledMapUtil.class.getName());  import java.util.SortedMap;
45    private static final SAXBuilder SAX_BUILDER = new SAXBuilder();  import java.util.TreeMap;
46    private static final XMLOutputter XML_OUTPUTTER = new XMLOutputter();  
47    import javax.swing.Box;
48    /** URL for Atlas XML schema */  import javax.swing.BoxLayout;
49    public static final String AMLURI = "http://www.wikisquare.de/AtlasML";  import javax.swing.ImageIcon;
50    /** Name of the XML Element for the attribute meta data map */  import javax.swing.JLabel;
51    public static final String ELEM_NAME_AMD = "attributeMetaData";  
52    /** Name of the XML Element for the raster legend data */  import org.apache.log4j.Logger;
53    public static final String ELEM_NAME_RLD = "rasterLegendData";  import org.geotools.coverage.grid.GridCoverage2D;
54    /** Name of the XML Element for an attribute meta data map entry */  import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader;
55    public static final String ELEM_NAME_ATTRIBUTE = "dataAttribute";  import org.geotools.feature.FeatureCollection;
56    /** Name of the XML Element for an raster legend data entry */  import org.geotools.map.DefaultMapLayer;
57    public static final String ELEM_NAME_RASTERLEGEND = "rasterLegendItem";  import org.geotools.map.MapLayer;
58    /** Name of the XML Element for a translation */  import org.geotools.styling.ColorMap;
59    public static final String ELEM_NAME_TRANSLATION = "translation";  import org.geotools.styling.ColorMapEntry;
60    import org.geotools.styling.FeatureTypeStyle;
61    /**  import org.geotools.styling.RasterSymbolizer;
62     * Creates a Geotools {@link MapLayer} from an object. If the object is a  import org.geotools.styling.Rule;
63     * {@link StyledMapInterface} then its sytle is used. In case of direct  import org.geotools.styling.Style;
64     * Geotools objects ({@link GridCoverage2D}, {@link AbstractGridCoverage2DReader},  import org.jdom.Document;
65     * {@link FeatureCollection}) a default style is generated.  import org.jdom.Element;
66     * @param object an Object  import org.jdom.input.SAXBuilder;
67     * @exception Exception if {@code null} is given as object or an error occurs during layer creation  import org.jdom.output.XMLOutputter;
68     */  import org.opengis.feature.simple.SimpleFeatureType;
69    public static MapLayer createMapLayer(Object object) throws Exception {  
70      return createMapLayer(object,null);  import schmitzm.geotools.styling.StylingUtil;
71    }  import schmitzm.io.IOUtil;
72    import schmitzm.lang.LangUtil;
73    /**  import schmitzm.swing.SwingUtil;
74     * Creates a Geotools {@link MapLayer} from an object. If the object is a  import skrueger.AttributeMetaData;
75     * {@link StyledMapInterface} then its sytle is used. In case of direct  import skrueger.RasterLegendData;
76     * Geotools objects ({@link GridCoverage2D}, {@link AbstractGridCoverage2DReader},  import skrueger.i8n.Translation;
77     * {@link FeatureCollection}) a default style is generated.  
78     * @param object an Object  /**
79     * @param forcedStyle (SLD-)Style to force for the object   * This class provides static helper methods for dealing with
80     * @exception Exception if {@code null} is given as object or an error occurs during layer creation   * {@link StyledLayerInterface} stuff.
81     */   * @author <a href="mailto:[email protected]">Martin Schmitz</a> (University of Bonn/Germany)
82    public static MapLayer createMapLayer(Object object, Style forcedStyle) throws Exception {   * @version 1.0
83      MapLayer layer     = null;   */
84      Style    style     = null;  public class StyledLayerUtil {
85      if ( object instanceof StyledMapInterface ) {    private static final Logger LOGGER = Logger.getLogger(StyledLayerUtil.class.getName());
86        style =  ((StyledMapInterface<?>)object).getStyle();    private static final SAXBuilder SAX_BUILDER = new SAXBuilder();
87        object = ((StyledMapInterface<?>)object).getGeoObject();    private static final XMLOutputter XML_OUTPUTTER = new XMLOutputter();
88      }  
89      if ( forcedStyle != null )    /** URL for Atlas XML schema */
90        style = forcedStyle;    public static final String AMLURI = "http://www.wikisquare.de/AtlasML";
91      if ( style == null )    /** Name of the XML Element for the attribute meta data map */
92        style = StylingUtil.createDefaultStyle(object);    public static final String ELEM_NAME_AMD = "attributeMetaData";
93      /** Name of the XML Element for the raster legend data */
94      if (object instanceof GridCoverage2D)    public static final String ELEM_NAME_RLD = "rasterLegendData";
95        layer = new DefaultMapLayer( (GridCoverage2D) object, style);    /** Name of the XML Element for an attribute meta data map entry */
96      if (object instanceof AbstractGridCoverage2DReader)    public static final String ELEM_NAME_ATTRIBUTE = "dataAttribute";
97        layer = new DefaultMapLayer( (AbstractGridCoverage2DReader) object, style);    /** Name of the XML Element for an raster legend data entry */
98      if (object instanceof FeatureCollection)    public static final String ELEM_NAME_RASTERLEGEND = "rasterLegendItem";
99        layer = new DefaultMapLayer( (FeatureCollection) object, style);    /** Name of the XML Element for a translation */
100      public static final String ELEM_NAME_TRANSLATION = "translation";
101      if ( layer == null )  
102        throw new Exception("Can not create MapLayer from "+(object == null ? "null" : object.getClass()));    /**
103       * Creates a Geotools {@link MapLayer} from an object. If the object is a
104      return layer;     * {@link StyledLayerInterface} then its sytle is used. In case of direct
105    }     * Geotools objects ({@link GridCoverage2D}, {@link AbstractGridCoverage2DReader},
106       * {@link FeatureCollection}) a default style is generated.
107    /**     * @param object an Object
108     * Creates an default instance of {@link StyledMapInterface} for a Geotools     * @exception Exception if {@code null} is given as object or an error occurs during layer creation
109     * object ({@link GridCoverage2D}, {@link FeatureCollection}) with a default     */
110     * style.    public static MapLayer createMapLayer(Object object) throws Exception {
111     * @param object an Object      return createMapLayer(object,null);
112     * @param title  title for the object    }
113     * @exception UnsupportedOperationException if {@code null} is given as object or an error occurs during creation  
114     */    /**
115    public static StyledMapInterface<?> createStyledMap(Object object, String title) {     * Creates a Geotools {@link MapLayer} from an object. If the object is a
116       return createStyledMap(object, title, null);     * {@link StyledLayerInterface} then its sytle is used. In case of direct
117    }     * Geotools objects ({@link GridCoverage2D}, {@link AbstractGridCoverage2DReader},
118       * {@link FeatureCollection}) a default style is generated.
119    /**     * @param object an Object
120     * Creates an default instance of {@link StyledMapInterface} for a Geotools     * @param forcedStyle (SLD-)Style to force for the object
121     * object ({@link GridCoverage2D}, {@link FeatureCollection}) with a given     * @exception Exception if {@code null} is given as object or an error occurs during layer creation
122     * style.     */
123     * @param object an Object    public static MapLayer createMapLayer(Object object, Style forcedStyle) throws Exception {
124     * @param title  title for the object      MapLayer layer     = null;
125     * @param style  style and meta data for the object      Style    style     = null;
126     * @exception UnsupportedOperationException if {@code null} is given as object or an error occurs during creation      if ( object instanceof StyledLayerInterface ) {
127     */        style =  ((StyledLayerInterface<?>)object).getStyle();
128    public static StyledMapInterface<?> createStyledMap(Object object, String title, StyledMapStyle style) {        object = ((StyledLayerInterface<?>)object).getGeoObject();
129      StyledMapInterface<?> styledObject = null;      }
130        if ( forcedStyle != null )
131      String id = (title != null) ? title : "defaultID";        style = forcedStyle;
132        if ( style == null )
133      if ( object instanceof GridCoverage2D )        style = StylingUtil.createDefaultStyle(object);
134        styledObject = new StyledGridCoverage(  
135            (GridCoverage2D)object,      if (object instanceof GridCoverage2D)
136            id,        layer = new DefaultMapLayer( (GridCoverage2D) object, style);
137            title,      if (object instanceof AbstractGridCoverage2DReader)
138            style        layer = new DefaultMapLayer( (AbstractGridCoverage2DReader) object, style);
139        );      if (object instanceof FeatureCollection)
140      else if ( object instanceof AbstractGridCoverage2DReader )        layer = new DefaultMapLayer( (FeatureCollection) object, style);
141             styledObject = new StyledGridCoverageReader(  
142                 (AbstractGridCoverage2DReader)object,      if ( layer == null )
143                 id,        throw new Exception("Can not create MapLayer from "+(object == null ? "null" : object.getClass()));
144                 title,  
145                 style      return layer;
146             );    }
147      else if ( object instanceof FeatureCollection )  
148        styledObject = new StyledFeatureCollection(    /**
149            (FeatureCollection)object,     * Creates an default instance of {@link StyledLayerInterface} for a Geotools
150            id,     * object ({@link GridCoverage2D}, {@link FeatureCollection}) with a default
151            title,     * style.
152            style     * @param object an Object
153        );     * @param title  title for the object
154           * @exception UnsupportedOperationException if {@code null} is given as object or an error occurs during creation
155      if ( styledObject == null )     */
156        throw new UnsupportedOperationException("Can not create StyledMapInterface object from "+(object == null ? "null" : object.getClass()));    public static StyledLayerInterface<?> createStyledLayer(Object object, String title) {
157         return createStyledLayer(object, title, null);
158      return styledObject;    }
159    }  
160      /**
161    /**     * Creates an default instance of {@link StyledLayerInterface} for a Geotools
162     * Return only the visible or invisible entries of an AttributeMetaData-Map.     * object ({@link GridCoverage2D}, {@link FeatureCollection}) with a given
163     * @param amdMap AttributeMetaData-Map     * style.
164     * @param visible indicated whether the visible or invisible entries are     * @param object an Object
165     *                returned     * @param title  title for the object
166     */     * @param style  style and meta data for the object
167    public static SortedMap<Integer,AttributeMetaData> getVisibleAttributeMetaData(Map<Integer,AttributeMetaData> amdMap, boolean visible) {     * @exception UnsupportedOperationException if {@code null} is given as object or an error occurs during creation
168      SortedMap<Integer,AttributeMetaData> filteredMap = new TreeMap<Integer,AttributeMetaData>();     */
169      for (AttributeMetaData amd : amdMap.values())    public static StyledLayerInterface<?> createStyledLayer(Object object, String title, StyledLayerStyle style) {
170        if ( amd.isVisible() )      StyledLayerInterface<?> styledLayer = null;
171          filteredMap.put(amd.getColIdx(), amd);  
172            String id = (title != null) ? title : "defaultID";
173      return filteredMap;  
174    }      if ( object instanceof GridCoverage2D )
175            styledLayer = new StyledGridCoverage(
176                (GridCoverage2D)object,
177    /**            id,
178     * Parses a {@link AttributeMetaData} object from an JDOM-{@link Element}.            title,
179     * This method works like {@link AMLImport#parseDataAttribute(org.w3c.dom.Node},            style
180     * but for JDOM.        );
181     * @param element {@link Element} to parse      else if ( object instanceof AbstractGridCoverage2DReader )
182     */             styledLayer = new StyledGridCoverageReader(
183    public static AttributeMetaData parseAttributeMetaData(final Element element) {                 (AbstractGridCoverage2DReader)object,
184      final Integer col = Integer.valueOf(element.getAttributeValue("col"));                 id,
185      final Boolean visible = Boolean.valueOf(element.getAttributeValue("visible"));                 title,
186      final String unit = element.getAttributeValue("unit");                 style
187               );
188      Translation name = new Translation();      else if ( object instanceof FeatureCollection )
189      Translation desc = new Translation();        styledLayer = new StyledFeatureCollection(
190      for (final Element childElement : (List<Element>)element.getChildren()) {            (FeatureCollection)object,
191        if (childElement.getName() == null)            id,
192          continue;            title,
193              style
194        if (childElement.getName().equals("name"))        );
195          name = parseTranslation(childElement);      
196        else if (childElement.getName().equals("desc"))      if ( styledLayer == null )
197          desc = parseTranslation(childElement);        throw new UnsupportedOperationException("Can not create StyledLayerInterface object from "+(object == null ? "null" : object.getClass()));
198      }  
199      return new AttributeMetaData(col, visible, name, desc, unit);      return styledLayer;
200    }    }
201    
202    /**    /**
203     * Parses a {@link AttributeMetaData} map from an JDOM-{@link Element}     * Return only the visible or invisible entries of an AttributeMetaData-Map.
204     * with {@code <attribute>}-childs.     * @param amdMap AttributeMetaData-Map
205     * @param element {@link Element} to parse     * @param visible indicated whether the visible or invisible entries are
206     */     *                returned
207    public static Map<Integer,AttributeMetaData> parseAttributeMetaDataMap(final Element element) {     */
208      HashMap<Integer,AttributeMetaData> metaData = new HashMap<Integer,AttributeMetaData>();    public static SortedMap<Integer,AttributeMetaData> getVisibleAttributeMetaData(Map<Integer,AttributeMetaData> amdMap, boolean visible) {
209      List<Element> attributesElements = element.getChildren( ELEM_NAME_ATTRIBUTE );      SortedMap<Integer,AttributeMetaData> filteredMap = new TreeMap<Integer,AttributeMetaData>();
210      for (Element attibuteElement : attributesElements)      for (AttributeMetaData amd : amdMap.values())
211      {        if ( amd.isVisible() )
212        AttributeMetaData attrMetaData = parseAttributeMetaData( attibuteElement );          filteredMap.put(amd.getColIdx(), amd);
213        metaData.put( attrMetaData.getColIdx(), attrMetaData );      
214      }      return filteredMap;
215      return metaData;    }
216    }    
217      
218    /**    /**
219     * Loads a {@link AttributeMetaData} object from an URL.     * Parses a {@link AttributeMetaData} object from an JDOM-{@link Element}.
220     * @param documentUrl {@link URL} to parse     * This method works like {@link AMLImport#parseDataAttribute(org.w3c.dom.Node},
221     * @see #parseAttributeMetaData(Element)     * but for JDOM.
222     */     * @param element {@link Element} to parse
223    public static Map<Integer,AttributeMetaData> loadAttributeMetaDataMap(final URL documentUrl) throws Exception {     */
224      Document document = SAX_BUILDER.build(documentUrl);    public static AttributeMetaData parseAttributeMetaData(final Element element) {
225      return parseAttributeMetaDataMap( document.getRootElement() );      final Integer col = Integer.valueOf(element.getAttributeValue("col"));
226    }      final Boolean visible = Boolean.valueOf(element.getAttributeValue("visible"));
227        final String unit = element.getAttributeValue("unit");
228    /**  
229     * Creates an JDOM {@link Element} for the given {@link AttributeMetaData}      Translation name = new Translation();
230     * object.      Translation desc = new Translation();
231     * @param amd meta data for one attribute      for (final Element childElement : (List<Element>)element.getChildren()) {
232     */        if (childElement.getName() == null)
233    public static Element createAttributeMetaDataElement(final AttributeMetaData amd) {          continue;
234      final Element element = new Element( ELEM_NAME_ATTRIBUTE , AMLURI);  
235      element.setAttribute("col", String.valueOf( amd.getColIdx() ) );        if (childElement.getName().equals("name"))
236      element.setAttribute("visible", String.valueOf( amd.isVisible() ) );          name = parseTranslation(childElement);
237      element.setAttribute("unit", amd.getUnit() );        else if (childElement.getName().equals("desc"))
238      // Creating a aml:name tag...          desc = parseTranslation(childElement);
239      element.addContent( createTranslationElement("name", amd.getTitle()) );      }
240      // Creating a aml:desc tag...      return new AttributeMetaData(col, visible, name, desc, unit);
241      element.addContent( createTranslationElement("desc", amd.getDesc()) );    }
242      return element;  
243    }    /**
244       * Parses a {@link AttributeMetaData} map from an JDOM-{@link Element}
245    /**     * with {@code <attribute>}-childs.
246     * Creates an JDOM {@link Element} for the given {@link AttributeMetaData}     * @param element {@link Element} to parse
247     * map.     */
248     * @param amdMap map of attribute meta data    public static Map<Integer,AttributeMetaData> parseAttributeMetaDataMap(final Element element) {
249     */      HashMap<Integer,AttributeMetaData> metaData = new HashMap<Integer,AttributeMetaData>();
250    public static Element createAttributeMetaDataMapElement(final Map<Integer,AttributeMetaData> amdMap) {      List<Element> attributesElements = element.getChildren( ELEM_NAME_ATTRIBUTE );
251      final Element element = new Element( ELEM_NAME_AMD , AMLURI);      for (Element attibuteElement : attributesElements)
252      for (AttributeMetaData amd : amdMap.values())      {
253        element.addContent( createAttributeMetaDataElement( amd ) );        AttributeMetaData attrMetaData = parseAttributeMetaData( attibuteElement );
254      return element;        metaData.put( attrMetaData.getColIdx(), attrMetaData );
255    }      }
256        return metaData;
257    /**    }
258     * Saves a {@link AttributeMetaData AttributeMetaData-Map} to an URL.  
259     * @param amdMap map of {@link AttributeMetaData}    /**
260     * @param documentUrl {@link URL} to store the XML     * Loads a {@link AttributeMetaData} object from an URL.
261     */     * @param documentUrl {@link URL} to parse
262    public static void saveAttributeMetaDataMap(final Map<Integer,AttributeMetaData> amdMap, final URL documentUrl) throws Exception {     * @see #parseAttributeMetaData(Element)
263      // Create XML-Document     */
264      final FileWriter out = new FileWriter( new File(documentUrl.toURI()) );    public static Map<Integer,AttributeMetaData> loadAttributeMetaDataMap(final URL documentUrl) throws Exception {
265      XML_OUTPUTTER.output(      Document document = SAX_BUILDER.build(documentUrl);
266        createAttributeMetaDataMapElement(amdMap),      return parseAttributeMetaDataMap( document.getRootElement() );
267        out    }
268      );  
269      out.flush();    /**
270      out.close();     * Creates an JDOM {@link Element} for the given {@link AttributeMetaData}
271    }     * object.
272       * @param amd meta data for one attribute
273       */
274      public static Element createAttributeMetaDataElement(final AttributeMetaData amd) {
275    /**      final Element element = new Element( ELEM_NAME_ATTRIBUTE , AMLURI);
276     * Parses a {@link RasterLegendData} object from an JDOM-{@link Element}.      element.setAttribute("col", String.valueOf( amd.getColIdx() ) );
277     * This method works like {@link AMLImport#parseRasterLegendData(org.w3c.dom.Node},      element.setAttribute("visible", String.valueOf( amd.isVisible() ) );
278     * but for JDOM.      element.setAttribute("unit", amd.getUnit() );
279     * @param element {@link Element} to parse      // Creating a aml:name tag...
280     */      element.addContent( createTranslationElement("name", amd.getTitle()) );
281    public static RasterLegendData parseRasterLegendData(Element element) {      // Creating a aml:desc tag...
282        element.addContent( createTranslationElement("desc", amd.getDesc()) );
283      final boolean paintGaps = Boolean.valueOf( element.getAttributeValue("paintGaps") );      return element;
284      }
285      RasterLegendData rld = new RasterLegendData(paintGaps);  
286      /**
287      for ( Element childElement : (List<Element>)element.getChildren() ) {     * Creates an JDOM {@link Element} for the given {@link AttributeMetaData}
288        final String name = childElement.getName();     * map.
289        // Cancel if it's an attribute     * @param amdMap map of attribute meta data
290        if ( childElement.getChildren().size() == 0 )     */
291          continue;    public static Element createAttributeMetaDataMapElement(final Map<Integer,AttributeMetaData> amdMap) {
292        final Element element = new Element( ELEM_NAME_AMD , AMLURI);
293        if (name.equals( ELEM_NAME_RASTERLEGEND )) {      for (AttributeMetaData amd : amdMap.values())
294          final String valueAttr = childElement.getAttributeValue("value");        element.addContent( createAttributeMetaDataElement( amd ) );
295          if ( valueAttr == null )      return element;
296            throw new UnsupportedOperationException("Attribute 'value' missing for definition of <"+ELEM_NAME_RASTERLEGEND+">");    }
297          final double value = Double.valueOf(valueAttr);  
298      /**
299          // first and only item should be the label     * Saves a {@link AttributeMetaData AttributeMetaData-Map} to an URL.
300          final Element labelElement = childElement.getChild("label");     * @param amdMap map of {@link AttributeMetaData}
301          // id label element is missing, the translation is searched directly     * @param documentUrl {@link URL} to store the XML
302          // as childs of the rasterLegendItem element     */
303          Translation label = parseTranslation( labelElement != null ? labelElement : childElement );    public static void saveAttributeMetaDataMap(final Map<Integer,AttributeMetaData> amdMap, final URL documentUrl) throws Exception {
304          rld.put(value, label);      // Create XML-Document
305        }      final FileWriter out = new FileWriter( new File(documentUrl.toURI()) );
306      }      XML_OUTPUTTER.output(
307          createAttributeMetaDataMapElement(amdMap),
308      return rld;        out
309    }      );
310        out.flush();
311    /**      out.close();
312     * Loads a {@link RasterLegendData} object from an URL.    }
313     * @param documentUrl {@link URL} to parse  
314     * @see #parseAttributeMetaData(Element)  
315     */  
316    public static RasterLegendData loadRasterLegendData(final URL documentUrl) throws Exception {    /**
317      Document document = SAX_BUILDER.build(documentUrl);     * Parses a {@link RasterLegendData} object from an JDOM-{@link Element}.
318      return parseRasterLegendData( document.getRootElement() );     * This method works like {@link AMLImport#parseRasterLegendData(org.w3c.dom.Node},
319    }     * but for JDOM.
320       * @param element {@link Element} to parse
321   /**     */
322     * Creates an JDOM {@link Element} for the given {@link RasterLegendData}    public static RasterLegendData parseRasterLegendData(Element element) {
323     * map.  
324     * @param rld raster legend data      final boolean paintGaps = Boolean.valueOf( element.getAttributeValue("paintGaps") );
325     */  
326    public static Element createRasterLegendDataElement(final RasterLegendData rld) {      RasterLegendData rld = new RasterLegendData(paintGaps);
327      final Element element = new Element( ELEM_NAME_RLD , AMLURI);  
328      element.setAttribute("paintGaps", rld.isPaintGaps().toString());      for ( Element childElement : (List<Element>)element.getChildren() ) {
329      for (Double key : rld.getSortedKeys()) {        final String name = childElement.getName();
330        Element item = new Element( ELEM_NAME_RASTERLEGEND, AMLURI);        // Cancel if it's an attribute
331        item.setAttribute("value", key.toString());        if ( childElement.getChildren().size() == 0 )
332        item.addContent( createTranslationElement("label", rld.get(key)) );          continue;
333        element.addContent(item);  
334      }        if (name.equals( ELEM_NAME_RASTERLEGEND )) {
335      return element;          final String valueAttr = childElement.getAttributeValue("value");
336    }          if ( valueAttr == null )
337              throw new UnsupportedOperationException("Attribute 'value' missing for definition of <"+ELEM_NAME_RASTERLEGEND+">");
338    /**          final double value = Double.valueOf(valueAttr);
339     * Creates {@link RasterLegendData} from a {@link ColorMap}.  
340     * @param colorMap  a color map          // first and only item should be the label
341     * @param paintGaps indicated whether gaps are painted between the legend items          final Element labelElement = childElement.getChild("label");
342     * @param digits    number of digits the grid value classes (and legend) are          // id label element is missing, the translation is searched directly
343     *                  rounded to (null means no round; >= 0 means digits after comma;          // as childs of the rasterLegendItem element
344     *                  < 0 means digits before comma)    */          Translation label = parseTranslation( labelElement != null ? labelElement : childElement );
345    public static RasterLegendData generateRasterLegendData(ColorMap colorMap, boolean paintGaps, Integer digits) {          rld.put(value, label);
346      DecimalFormat    decFormat = digits != null ? new DecimalFormat( SwingUtil.getNumberFormatPattern(digits) ) : null;        }
347      RasterLegendData rld       = new RasterLegendData(paintGaps);      }
348      for (ColorMapEntry cme : colorMap.getColorMapEntries())  
349      {      return rld;
350        double value = StylingUtil.getQuantityFromColorMapEntry(cme);    }
351        String label = cme.getLabel();  
352        // if no label is set (e.g. quantitative style),    /**
353        // use the value as label     * Loads a {@link RasterLegendData} object from an URL.
354        if ( label == null || label.equals("") )     * @param documentUrl {@link URL} to parse
355          if ( digits == null )     * @see #parseAttributeMetaData(Element)
356            label = String.valueOf(value);     */
357          else    public static RasterLegendData loadRasterLegendData(final URL documentUrl) throws Exception {
358            label = decFormat.format( LangUtil.round(value, digits) );      Document document = SAX_BUILDER.build(documentUrl);
359        rld.put( value, new Translation("   "+label) );      return parseRasterLegendData( document.getRootElement() );
360      }    }
361      return rld;  
362    }   /**
363       * Creates an JDOM {@link Element} for the given {@link RasterLegendData}
364    /**     * map.
365     * Creates {@link RasterLegendData} from the {@link ColorMap} of a style.     * @param rld raster legend data
366     * @param style     a raster style (must contain a  {@link RasterSymbolizer})     */
367     * @param paintGaps indicated whether gaps are painted between the legend items    public static Element createRasterLegendDataElement(final RasterLegendData rld) {
368     * @param digits    number of digits the grid value classes (and legend) are      final Element element = new Element( ELEM_NAME_RLD , AMLURI);
369     *                  rounded to (null means no round; >= 0 means digits after comma;      element.setAttribute("paintGaps", rld.isPaintGaps().toString());
370     *                  < 0 means digits before comma)    */      for (Double key : rld.getSortedKeys()) {
371    public static RasterLegendData generateRasterLegendData(Style style, boolean paintGaps, Integer digits) {        Element item = new Element( ELEM_NAME_RASTERLEGEND, AMLURI);
372      ColorMap colorMap = StylingUtil.getColorMapFromStyle(style);        item.setAttribute("value", key.toString());
373      if ( colorMap == null)        item.addContent( createTranslationElement("label", rld.get(key)) );
374        throw new IllegalArgumentException("Color map can not be determined from style!");        element.addContent(item);
375      return generateRasterLegendData(colorMap, paintGaps, digits);      }
376    }      return element;
377      }
378    /**  
379     * Saves a {@link RasterLegendData} to an URL.    /**
380     * @param rld raster legend data     * Creates {@link RasterLegendData} from a {@link ColorMap}.
381     * @param documentUrl {@link URL} to store the XML     * @param colorMap  a color map
382     */     * @param paintGaps indicated whether gaps are painted between the legend items
383    public static void saveRasterLegendData(final RasterLegendData rld, final URL documentUrl) throws Exception {     * @param digits    number of digits the grid value classes (and legend) are
384      // Create XML-Document     *                  rounded to (null means no round; >= 0 means digits after comma;
385      final FileWriter out = new FileWriter( new File(documentUrl.toURI()) );     *                  < 0 means digits before comma)    */
386      XML_OUTPUTTER.output(    public static RasterLegendData generateRasterLegendData(ColorMap colorMap, boolean paintGaps, Integer digits) {
387        createRasterLegendDataElement(rld),      DecimalFormat    decFormat = digits != null ? new DecimalFormat( SwingUtil.getNumberFormatPattern(digits) ) : null;
388        out      RasterLegendData rld       = new RasterLegendData(paintGaps);
389      );      for (ColorMapEntry cme : colorMap.getColorMapEntries())
390      out.flush();      {
391      out.close();        double value = StylingUtil.getQuantityFromColorMapEntry(cme);
392    }        String label = cme.getLabel();
393          // if no label is set (e.g. quantitative style),
394    /**        // use the value as label
395     * Parses a {@link Translation} object from an JDOM-{@link Element}.        if ( label == null || label.equals("") )
396     * This method works like {@link AMLImport#parseTranslation(org.w3c.dom.Node},          if ( digits == null )
397     * but for JDOM.            label = String.valueOf(value);
398     * @param element {@link Element} to parse          else
399     */            label = decFormat.format( LangUtil.round(value, digits) );
400    public final static Translation parseTranslation(final Element element) {        rld.put( value, new Translation("   "+label) );
401      Translation trans = new Translation();      }
402        return rld;
403      if (element == null)    }
404       return trans;  
405      /**
406      for (final Element translationElement : (List<Element>)element.getChildren()) {     * Creates {@link RasterLegendData} from the {@link ColorMap} of a style.
407        final String name = translationElement.getName();     * @param style     a raster style (must contain a  {@link RasterSymbolizer})
408        if (name == null)     * @param paintGaps indicated whether gaps are painted between the legend items
409          continue;     * @param digits    number of digits the grid value classes (and legend) are
410       *                  rounded to (null means no round; >= 0 means digits after comma;
411        // lang attribute     *                  < 0 means digits before comma)    */
412        String lang = translationElement.getAttributeValue("lang");    public static RasterLegendData generateRasterLegendData(Style style, boolean paintGaps, Integer digits) {
413        // set the default, if no language code is set      ColorMap colorMap = StylingUtil.getColorMapFromStyle(style);
414        if ( lang == null )      if ( colorMap == null)
415          lang = Translation.DEFAULT_KEY;        throw new IllegalArgumentException("Color map can not be determined from style!");
416        return generateRasterLegendData(colorMap, paintGaps, digits);
417        final String translationText = translationElement.getValue();    }
418        if (translationText == null)  
419          trans.put(lang, "");    /**
420        else     * Saves a {@link RasterLegendData} to an URL.
421          trans.put(lang, translationText);     * @param rld raster legend data
422      }     * @param documentUrl {@link URL} to store the XML
423       */
424      // if no <translation> is given, the value of the node should    public static void saveRasterLegendData(final RasterLegendData rld, final URL documentUrl) throws Exception {
425      // be used as a default translation      // Create XML-Document
426      if (trans.size() == 0)      final FileWriter out = new FileWriter( new File(documentUrl.toURI()) );
427        trans.put( Translation.DEFAULT_KEY, element.getValue() );      XML_OUTPUTTER.output(
428      //     trans = new Translation( ((List<Element>)element.getChildren()).get(0).getValue() );        createRasterLegendDataElement(rld),
429          out
430      return trans;      );
431    }      out.flush();
432        out.close();
433    /**    }
434     * Creates an JDOM {@link Element} for the given {@link Translation}.  
435     * @param tagname Name of the Element    /**
436     * @param translation Translation to store in the Element     * Parses a {@link Translation} object from an JDOM-{@link Element}.
437     */     * This method works like {@link AMLImport#parseTranslation(org.w3c.dom.Node},
438    public final static Element createTranslationElement(String tagname, Translation translation) {     * but for JDOM.
439      Element element = new Element(tagname, AMLURI);     * @param element {@link Element} to parse
440      if ( translation == null )     */
441        throw new UnsupportedOperationException("Translation element can not be created from null!");    public final static Translation parseTranslation(final Element element) {
442        Translation trans = new Translation();
443      // If only a default translation is set, the <translation lang="..">..</tranlation>  
444      // part is not used      if (element == null)
445      if (translation.keySet().size() == 1 && translation.get(Translation.DEFAULT_KEY) != null) {       return trans;
446        element.addContent( translation.get(Translation.DEFAULT_KEY) );  
447        return element;      for (final Element translationElement : (List<Element>)element.getChildren()) {
448      }        final String name = translationElement.getName();
449          if (name == null)
450      // add a <translation lang="..">..</tranlation> part to the element for          continue;
451      // all languages  
452      for (String lang : translation.keySet()) {        // lang attribute
453        Element translationElement = new Element( ELEM_NAME_TRANSLATION , AMLURI);        String lang = translationElement.getAttributeValue("lang");
454        translationElement.setAttribute("lang", lang);        // set the default, if no language code is set
455        String translationString = translation.get(lang);        if ( lang == null )
456        if (translationString == null)          lang = Translation.DEFAULT_KEY;
457         translationString = "";  
458        translationElement.addContent( translationString );        final String translationText = translationElement.getValue();
459        element.addContent(translationElement);        if (translationText == null)
460      }          trans.put(lang, "");
461          else
462      return element;          trans.put(lang, translationText);
463    }      }
464    
465        // if no <translation> is given, the value of the node should
466    /**      // be used as a default translation
467     * Sets a style to {@link StyledMapInterface}.      if (trans.size() == 0)
468     * @param styledObject a styled object        trans.put( Translation.DEFAULT_KEY, element.getValue() );
469     * @param style a Style      //     trans = new Translation( ((List<Element>)element.getChildren()).get(0).getValue() );
470     */  
471    public static void setStyledMapStyle(StyledMapInterface styledObject, StyledMapStyle<?> style) {      return trans;
472      // set SLD style    }
473      styledObject.setStyle( style.getGeoObjectStyle() );  
474      // set meta data    /**
475      if ( styledObject        instanceof StyledGridCoverageInterface &&     * Creates an JDOM {@link Element} for the given {@link Translation}.
476           (style.getMetaData() instanceof RasterLegendData || style.getMetaData() == null) ) {     * @param tagname Name of the Element
477        RasterLegendData sourceRld = (RasterLegendData)style.getMetaData();     * @param translation Translation to store in the Element
478        RasterLegendData destRld = ((StyledGridCoverageInterface)styledObject).getLegendMetaData();     */
479        if ( destRld != null && sourceRld != null ) {    public final static Element createTranslationElement(String tagname, Translation translation) {
480          destRld.setPaintGaps(sourceRld.isPaintGaps());      Element element = new Element(tagname, AMLURI);
481          destRld.clear();      if ( translation == null )
482          destRld.putAll( sourceRld );        throw new UnsupportedOperationException("Translation element can not be created from null!");
483        }  
484        return;      // If only a default translation is set, the <translation lang="..">..</tranlation>
485      }      // part is not used
486      if ( styledObject        instanceof StyledFeatureCollectionInterface &&      if (translation.keySet().size() == 1 && translation.get(Translation.DEFAULT_KEY) != null) {
487           (style.getMetaData() instanceof Map || style.getMetaData() == null) ) {        element.addContent( translation.get(Translation.DEFAULT_KEY) );
488        Map<Integer, AttributeMetaData> sourceAmd = (Map<Integer, AttributeMetaData>)style.getMetaData();        return element;
489        Map<Integer, AttributeMetaData> destAmd   = ((StyledFeatureCollectionInterface)styledObject).getAttributeMetaDataMap();      }
490        if ( destAmd != null && sourceAmd != null ) {  
491          destAmd.clear();      // add a <translation lang="..">..</tranlation> part to the element for
492          destAmd.putAll( sourceAmd );      // all languages
493        }      for (String lang : translation.keySet()) {
494        return;        Element translationElement = new Element( ELEM_NAME_TRANSLATION , AMLURI);
495      }        translationElement.setAttribute("lang", lang);
496          String translationString = translation.get(lang);
497      throw new UnsupportedOperationException("Style is not compatible to object: " +        if (translationString == null)
498                                              (style.getMetaData() == null ? null : style.getMetaData().getClass().getSimpleName()) +         translationString = "";
499                                              " <-> " +        translationElement.addContent( translationString );
500                                              (styledObject == null ? null : styledObject.getClass().getSimpleName()));        element.addContent(translationElement);
501    }      }
502    
503    /**      return element;
504     * Returns the style a {@link StyledMapInterface} as a {@link StyledMapStyle}.    }
505     * @param styledObject a styled object  
506     * @return {@code StyledMapStyle<RasterLegendData>} for {@link StyledGridCoverageInterface}  
507     *         or {@code StyledMapStyle<Map<Integer,AttributeMetaData>>} for    /**
508     *         {@link StyledFeatureCollectionInterface}     * Sets a style to {@link StyledLayerInterface}.
509     */     * @param styledObject a styled object
510    public static StyledMapStyle<?> getStyledMapStyle(StyledMapInterface styledObject) {     * @param style a Style
511      if ( styledObject instanceof StyledGridCoverageInterface )     */
512        return getStyledMapStyle( (StyledGridCoverageInterface)styledObject );    public static void setStyledLayerStyle(StyledLayerInterface styledObject, StyledLayerStyle<?> style) {
513      if ( styledObject instanceof StyledFeatureCollectionInterface )      // set SLD style
514        return getStyledMapStyle( (StyledFeatureCollectionInterface)styledObject );      styledObject.setStyle( style.getGeoObjectStyle() );
515      throw new UnsupportedOperationException("Unknown type of StyledMapInterface: "+(styledObject == null ? null : styledObject.getClass().getSimpleName()));      // set meta data
516    }      if ( styledObject        instanceof StyledGridCoverageInterface &&
517             (style.getMetaData() instanceof RasterLegendData || style.getMetaData() == null) ) {
518    /**        RasterLegendData sourceRld = (RasterLegendData)style.getMetaData();
519     * Returns the style and raster meta data of a {@link StyledGridCoverageInterface}        RasterLegendData destRld = ((StyledGridCoverageInterface)styledObject).getLegendMetaData();
520     * as a {@link StyledMapStyle}.        if ( destRld != null && sourceRld != null ) {
521     * @param styledGC a styled grid coverage          destRld.setPaintGaps(sourceRld.isPaintGaps());
522     */          destRld.clear();
523    public static StyledMapStyle<RasterLegendData> getStyledMapStyle(StyledGridCoverageInterface styledGC) {          destRld.putAll( sourceRld );
524      return new StyledMapStyle<RasterLegendData>(        }
525        styledGC.getStyle(),        return;
526        styledGC.getLegendMetaData()      }
527      );      if ( styledObject        instanceof StyledFeatureCollectionInterface &&
528    }           (style.getMetaData() instanceof Map || style.getMetaData() == null) ) {
529          Map<Integer, AttributeMetaData> sourceAmd = (Map<Integer, AttributeMetaData>)style.getMetaData();
530    /**        Map<Integer, AttributeMetaData> destAmd   = ((StyledFeatureCollectionInterface)styledObject).getAttributeMetaDataMap();
531     * Returns the style and attribute meta data of a {@link StyledFeatureCollectionInterface}        if ( destAmd != null && sourceAmd != null ) {
532     * as a {@link StyledMapStyle}.          destAmd.clear();
533     * @param styledFC a styled feature collection          destAmd.putAll( sourceAmd );
534     */        }
535    public static StyledMapStyle<Map<Integer,AttributeMetaData>> getStyledMapStyle(StyledFeatureCollectionInterface styledFC) {        return;
536      return new StyledMapStyle<Map<Integer,AttributeMetaData>>(      }
537        styledFC.getStyle(),  
538        styledFC.getAttributeMetaDataMap()      throw new UnsupportedOperationException("Style is not compatible to object: " +
539      );                                              (style.getMetaData() == null ? null : style.getMetaData().getClass().getSimpleName()) +
540    }                                              " <-> " +
541                                                (styledObject == null ? null : styledObject.getClass().getSimpleName()));
542    /**    }
543     * Loads a {@linkplain Style SLD-Style} and {@linkplain RasterLegendData Raster-LegendData}  
544     * for a given geo-object (raster) source. The SLD file must be present. A missing    /**
545     * raster legend-data file is tolerated.     * Returns the style a {@link StyledLayerInterface} as a {@link StyledLayerStyle}.
546     * @param geoObjectURL URL of the (already read) raster object     * @param styledObject a styled object
547     * @param sldExt file extention for the SLD file     * @return {@code StyledLayerStyle<RasterLegendData>} for {@link StyledGridCoverageInterface}
548     * @param rldExt file extention for the raster legend-data file     *         or {@code StyledLayerStyle<Map<Integer,AttributeMetaData>>} for
549     * @return {@code null} in case of any error     *         {@link StyledFeatureCollectionInterface}
550     */     */
551    public static StyledMapStyle<RasterLegendData> loadStyledRasterStyle(URL geoObjectURL, String sldExt, String rldExt) {    public static StyledLayerStyle<?> getStyledLayerStyle(StyledLayerInterface styledObject) {
552      RasterLegendData metaData = null;      if ( styledObject instanceof StyledGridCoverageInterface )
553      Style sldStyle = null;        return getStyledLayerStyle( (StyledGridCoverageInterface)styledObject );
554      try {      if ( styledObject instanceof StyledFeatureCollectionInterface )
555        Style[] styles = StylingUtil.loadSLD(IOUtil.changeUrlExt(geoObjectURL, sldExt));        return getStyledLayerStyle( (StyledFeatureCollectionInterface)styledObject );
556        // SLD must be present      throw new UnsupportedOperationException("Unknown type of StyledLayerInterface: "+(styledObject == null ? null : styledObject.getClass().getSimpleName()));
557        if ( styles == null || styles.length == 0 )    }
558          return null;  
559        sldStyle = styles[0];    /**
560      }     * Returns the style and raster meta data of a {@link StyledGridCoverageInterface}
561      catch (Exception err) {     * as a {@link StyledLayerStyle}.
562        // SLD must be present     * @param styledGC a styled grid coverage
563        LangUtil.logDebugError(LOGGER,err);     */
564        return null;    public static StyledLayerStyle<RasterLegendData> getStyledLayerStyle(StyledGridCoverageInterface styledGC) {
565      }      return new StyledLayerStyle<RasterLegendData>(
566          styledGC.getStyle(),
567      try {        styledGC.getLegendMetaData()
568        metaData = StyledMapUtil.loadRasterLegendData( IOUtil.changeUrlExt(geoObjectURL,rldExt) );      );
569      } catch (FileNotFoundException err) {    }
570        // ignore missing raster legend data  
571      } catch (Exception err) {    /**
572        // any other error during legend data creation leads to error     * Returns the style and attribute meta data of a {@link StyledFeatureCollectionInterface}
573        LangUtil.logDebugError(LOGGER,err);     * as a {@link StyledLayerStyle}.
574        return null;     * @param styledFC a styled feature collection
575      }     */
576      return new StyledMapStyle<RasterLegendData>(sldStyle, metaData);    public static StyledLayerStyle<Map<Integer,AttributeMetaData>> getStyledLayerStyle(StyledFeatureCollectionInterface styledFC) {
577    }      return new StyledLayerStyle<Map<Integer,AttributeMetaData>>(
578          styledFC.getStyle(),
579    /**        styledFC.getAttributeMetaDataMap()
580     * Loads a {@linkplain Style SLD-Style} from a {@code .sld} file and      );
581     * {@linkplain RasterLegendData Raster-LegendData} from a {@code .rld} file    }
582     * for a given geo-object (raster) source. The SLD file must be present. A missing  
583     * raster legend-data file is tolerated.    /**
584     * @param geoObjectURL URL of the (already read) raster object     * Loads a {@linkplain Style SLD-Style} and {@linkplain RasterLegendData Raster-LegendData}
585     * @param sldExt file extention for the SLD file     * for a given geo-object (raster) source. The SLD file must be present. A missing
586     * @param rldExt file extention for the raster legend-data file     * raster legend-data file is tolerated.
587     * @return {@code null} in case of any error     * @param geoObjectURL URL of the (already read) raster object
588     */     * @param sldExt file extention for the SLD file
589    public static StyledMapStyle<RasterLegendData> loadStyledRasterStyle(URL geoObjectURL) {     * @param rldExt file extention for the raster legend-data file
590      return loadStyledRasterStyle(geoObjectURL, "sld", "rld");     * @return {@code null} in case of any error
591    }     */
592      public static StyledLayerStyle<RasterLegendData> loadStyledRasterStyle(URL geoObjectURL, String sldExt, String rldExt) {
593    /**      RasterLegendData metaData = null;
594     * Loads a {@linkplain Style SLD-Style} and a {@linkplain AttributeMetaData AttributeMetaData-Map}      Style sldStyle = null;
595     * for a given geo-object (feature) source. The SLD file must be present. A missing      try {
596     * attribute meta-data file is tolerated.        Style[] styles = StylingUtil.loadSLD(IOUtil.changeUrlExt(geoObjectURL, sldExt));
597     * @param geoObjectURL URL of the (already read) feature object        // SLD must be present
598     * @param sldExt file extention for the SLD file        if ( styles == null || styles.length == 0 )
599     * @param rldExt file extention for the raster legend-data file          return null;
600     * @return {@code null} in case of any error        sldStyle = styles[0];
601     */      }
602    public static StyledMapStyle<Map<Integer,AttributeMetaData>> loadStyledFeatureStyle(URL geoObjectURL, String sldExt, String rldExt) {      catch (Exception err) {
603      Map<Integer,AttributeMetaData> metaData = null;        // SLD must be present
604      Style                          sldStyle = null;        LangUtil.logDebugError(LOGGER,err);
605      try {        return null;
606        Style[] styles = StylingUtil.loadSLD(IOUtil.changeUrlExt(geoObjectURL, sldExt));      }
607        // SLD must be present  
608        if ( styles == null || styles.length == 0 )      try {
609          return null;        metaData = StyledLayerUtil.loadRasterLegendData( IOUtil.changeUrlExt(geoObjectURL,rldExt) );
610        sldStyle = styles[0];      } catch (FileNotFoundException err) {
611      } catch (Exception err) {        // ignore missing raster legend data
612        // SLD must be present      } catch (Exception err) {
613        LangUtil.logDebugError(LOGGER,err);        // any other error during legend data creation leads to error
614        return null;        LangUtil.logDebugError(LOGGER,err);
615      }        return null;
616        }
617      try {      return new StyledLayerStyle<RasterLegendData>(sldStyle, metaData);
618        metaData = StyledMapUtil.loadAttributeMetaDataMap( IOUtil.changeUrlExt(geoObjectURL,rldExt) );    }
619      } catch (FileNotFoundException err) {  
620        // ignore missing attribute meta data    /**
621      } catch (Exception err) {     * Loads a {@linkplain Style SLD-Style} from a {@code .sld} file and
622        // any other error during meta data creation leads to error     * {@linkplain RasterLegendData Raster-LegendData} from a {@code .rld} file
623        LangUtil.logDebugError(LOGGER,err);     * for a given geo-object (raster) source. The SLD file must be present. A missing
624        return null;     * raster legend-data file is tolerated.
625      }     * @param geoObjectURL URL of the (already read) raster object
626       * @param sldExt file extention for the SLD file
627      return new StyledMapStyle<Map<Integer,AttributeMetaData>>(sldStyle, metaData);     * @param rldExt file extention for the raster legend-data file
628    }     * @return {@code null} in case of any error
629       */
630    /**    public static StyledLayerStyle<RasterLegendData> loadStyledRasterStyle(URL geoObjectURL) {
631     * Loads a {@linkplain Style SLD-Style} from a {@code .sld} file and      return loadStyledRasterStyle(geoObjectURL, "sld", "rld");
632     * {@linkplain AttributeMetaData AttributeMetaData-Map} from a {@code .amd} file    }
633     * for a given geo-object (feature) source. The SLD file must be present. A missing  
634     * attribute meta-data file is tolerated.    /**
635     * @param geoObjectURL URL of the (already read) feature object     * Loads a {@linkplain Style SLD-Style} and a {@linkplain AttributeMetaData AttributeMetaData-Map}
636     * @param sldExt file extention for the SLD file     * for a given geo-object (feature) source. The SLD file must be present. A missing
637     * @param rldExt file extention for the raster legend-data file     * attribute meta-data file is tolerated.
638     * @return {@code null} in case of any error     * @param geoObjectURL URL of the (already read) feature object
639     */     * @param sldExt file extention for the SLD file
640    public static StyledMapStyle<Map<Integer,AttributeMetaData>> loadStyledFeatureStyle(URL geoObjectURL) {     * @param rldExt file extention for the raster legend-data file
641      return loadStyledFeatureStyle(geoObjectURL, "sld", "amd");     * @return {@code null} in case of any error
642    }     */
643      public static StyledLayerStyle<Map<Integer,AttributeMetaData>> loadStyledFeatureStyle(URL geoObjectURL, String sldExt, String rldExt) {
644    /**      Map<Integer,AttributeMetaData> metaData = null;
645     * Stores a {@linkplain Style SLD-Style} and {@linkplain RasterLegendData Raster-LegendData}      Style                          sldStyle = null;
646     * for a given geo-object (raster) source.      try {
647     * @param style  style to save        Style[] styles = StylingUtil.loadSLD(IOUtil.changeUrlExt(geoObjectURL, sldExt));
648     * @param geoObjectURL URL of the raster object        // SLD must be present
649     * @param sldExt file extention for the SLD file        if ( styles == null || styles.length == 0 )
650     * @param mdExt file extention for the meta-data file          return null;
651     */        sldStyle = styles[0];
652    public static <T> void saveStyledMapStyle(StyledMapStyle<T> style, URL geoObjectURL, String sldExt, String mdExt) throws Exception {      } catch (Exception err) {
653      // Store the SLD        // SLD must be present
654      Style sldStyle = style.getGeoObjectStyle();        LangUtil.logDebugError(LOGGER,err);
655      if ( sldStyle != null ) {        return null;
656        StylingUtil.saveStyleToSLD(      }
657           sldStyle,  
658           IOUtil.changeFileExt(      try {
659                new File(geoObjectURL.toURI()),        metaData = StyledLayerUtil.loadAttributeMetaDataMap( IOUtil.changeUrlExt(geoObjectURL,rldExt) );
660                sldExt      } catch (FileNotFoundException err) {
661           )        // ignore missing attribute meta data
662        );      } catch (Exception err) {
663      }        // any other error during meta data creation leads to error
664          LangUtil.logDebugError(LOGGER,err);
665      // Store the meta data        return null;
666      T metaData = style.getMetaData();      }
667      if ( metaData != null ) {  
668        if ( metaData instanceof RasterLegendData ) {      return new StyledLayerStyle<Map<Integer,AttributeMetaData>>(sldStyle, metaData);
669          saveRasterLegendData(    }
670              (RasterLegendData)metaData,  
671              IOUtil.changeUrlExt(geoObjectURL,mdExt)    /**
672          );     * Loads a {@linkplain Style SLD-Style} from a {@code .sld} file and
673  //      } else if ( metaData instanceof Map<Integer,AttributeMetaData> ) { // LEIDER NICHT KOMPILIERBAR!!     * {@linkplain AttributeMetaData AttributeMetaData-Map} from a {@code .amd} file
674        } else if ( metaData instanceof Map ) {     * for a given geo-object (feature) source. The SLD file must be present. A missing
675          saveAttributeMetaDataMap(     * attribute meta-data file is tolerated.
676              (Map<Integer,AttributeMetaData>)metaData,     * @param geoObjectURL URL of the (already read) feature object
677              IOUtil.changeUrlExt(geoObjectURL,mdExt)     * @param sldExt file extention for the SLD file
678          );     * @param rldExt file extention for the raster legend-data file
679        } else     * @return {@code null} in case of any error
680          throw new UnsupportedOperationException("Export for meta data not yet supported: "+metaData.getClass().getSimpleName());     */
681      }    public static StyledLayerStyle<Map<Integer,AttributeMetaData>> loadStyledFeatureStyle(URL geoObjectURL) {
682    }      return loadStyledFeatureStyle(geoObjectURL, "sld", "amd");
683      }
684    /**  
685     * Stores the {@linkplain Style SLD-Style} to a {@code .sld} file and    /**
686     * the meta data ({@link RasterLegendData} or {@link AttributeMetaData})     * Stores a {@linkplain Style SLD-Style} and {@linkplain RasterLegendData Raster-LegendData}
687     * to a {@code .rld} or {@code .amd} file.     * for a given geo-object (raster) source.
688     * for a given geo-object source.     * @param style  style to save
689     * @param style  style to save     * @param geoObjectURL URL of the raster object
690     * @param geoObjectURL URL of the (already read) raster object     * @param sldExt file extention for the SLD file
691     */     * @param mdExt file extention for the meta-data file
692    public static void saveStyledMapStyle(StyledMapStyle<?> style, URL geoObjectURL) throws Exception {     */
693      if ( style.getMetaData() instanceof RasterLegendData )    public static <T> void saveStyledLayerStyle(StyledLayerStyle<T> style, URL geoObjectURL, String sldExt, String mdExt) throws Exception {
694        saveStyledMapStyle(style,geoObjectURL, "sld", "rld");      // Store the SLD
695      else      Style sldStyle = style.getGeoObjectStyle();
696        saveStyledMapStyle(style,geoObjectURL, "sld", "amd");      if ( sldStyle != null ) {
697    }        StylingUtil.saveStyleToSLD(
698             sldStyle,
699  }           IOUtil.changeFileExt(
700                  new File(geoObjectURL.toURI()),
701                  sldExt
702             )
703          );
704        }
705    
706        // Store the meta data
707        T metaData = style.getMetaData();
708        if ( metaData != null ) {
709          if ( metaData instanceof RasterLegendData ) {
710            saveRasterLegendData(
711                (RasterLegendData)metaData,
712                IOUtil.changeUrlExt(geoObjectURL,mdExt)
713            );
714    //      } else if ( metaData instanceof Map<Integer,AttributeMetaData> ) { // LEIDER NICHT KOMPILIERBAR!!
715          } else if ( metaData instanceof Map ) {
716            saveAttributeMetaDataMap(
717                (Map<Integer,AttributeMetaData>)metaData,
718                IOUtil.changeUrlExt(geoObjectURL,mdExt)
719            );
720          } else
721            throw new UnsupportedOperationException("Export for meta data not yet supported: "+metaData.getClass().getSimpleName());
722        }
723      }
724    
725      /**
726       * Stores the {@linkplain Style SLD-Style} to a {@code .sld} file and
727       * the meta data ({@link RasterLegendData} or {@link AttributeMetaData})
728       * to a {@code .rld} or {@code .amd} file.
729       * for a given geo-object source.
730       * @param style  style to save
731       * @param geoObjectURL URL of the (already read) raster object
732       */
733      public static void saveStyledLayerStyle(StyledLayerStyle<?> style, URL geoObjectURL) throws Exception {
734        if ( style.getMetaData() instanceof RasterLegendData )
735          saveStyledLayerStyle(style,geoObjectURL, "sld", "rld");
736        else
737          saveStyledLayerStyle(style,geoObjectURL, "sld", "amd");
738      }
739      
740      
741    
742            /**
743             * Creates a {@link Box} that shows a legend for a list of
744             * {@link FeatureTypeStyle}s and a targeted featureType
745             *
746             * @param featureType
747             *            If this a legend for Point, Polygon or Line?
748             * @param list
749             *            The Styles to presented in this legend
750             *
751             * @author <a href="mailto:[email protected]">Stefan Alfons
752             *         Kr&uuml;ger</a>
753             */
754            public static Box createLegendPanel(List<FeatureTypeStyle> list,
755                            SimpleFeatureType featureType, int iconWidth, int iconHeight) {
756    
757                    Box box = new Box(BoxLayout.Y_AXIS) {
758    
759                            /**
760                             * Nuetzlich wenn die Componente gedruckt (z.B. wenn ein Screenshot
761                             * gemacht wird) wird. Dann werden wird der Hintergrund auf WEISS
762                             * gesetzt.
763                             *
764                             * @author <a href="mailto:[email protected]">Stefan Alfons
765                             *         Kr&uuml;ger</a>
766                             */
767                            @Override
768                            public void print(Graphics g) {
769                                    final Color orig = getBackground();
770                                    setBackground(Color.WHITE);
771                                    // wrap in try/finally so that we always restore the state
772                                    try {
773                                            super.print(g);
774                                    } finally {
775                                            setBackground(orig);
776                                    }
777                            }
778                    };
779    
780                    for (FeatureTypeStyle ftStyle : list) {
781    
782                            // One child-node for every rule
783                            List<Rule> rules = ftStyle.rules();
784                            for (Rule rule : rules) {
785    
786                                    /**
787                                     * Let's not create a hbox for Rules that only contain
788                                     * TextSymbolizers
789                                     */
790                                    if (StylingUtil.getTextSymbolizers(rule.getSymbolizers())
791                                                    .size() == rule.getSymbolizers().length)
792                                            continue;
793    
794                                    Box hbox = new Box(BoxLayout.X_AXIS) {
795    
796                                            /**
797                                             * Nuetzlich wenn die Componente gedruckt (z.B. wenn ein
798                                             * Screenshot gemacht wird) wird. Dann werden wird der
799                                             * Hintergrund auf WEISS gesetzt.
800                                             *
801                                             * @author <a href="mailto:[email protected]">Stefan
802                                             *         Alfons Kr&uuml;ger</a>
803                                             */
804                                            @Override
805                                            public void print(Graphics g) {
806                                                    final Color orig = getBackground();
807                                                    setBackground(Color.WHITE);
808                                                    // wrap in try/finally so that we always restore the
809                                                    // state
810                                                    try {
811                                                            super.print(g);
812                                                    } finally {
813                                                            setBackground(orig);
814                                                    }
815                                            }
816                                    };
817    
818                                    /**
819                                     * The size of the legend Symbol is dependent on the size of the
820                                     * font.
821                                     */
822                                    final int fontHeight = new JLabel().getFontMetrics(
823                                                    new JLabel().getFont()).getHeight();
824                                    
825                                    final Dimension ICON_SIZE = new Dimension(iconWidth,
826                                                    fontHeight > 5 ? fontHeight : iconHeight);
827    
828                                    // ****************************************************************************
829                                    // Create the actual icon
830                                    // ****************************************************************************
831                                    final BufferedImage imageForRule = LegendIconFeatureRenderer
832                                                    .getInstance().createImageForRule(rule, featureType,
833                                                                    ICON_SIZE);
834    
835                                    // LOGGER.debug("Creating a new Legend Image for RUle name =
836                                    // "+rule.getName());
837    
838                                    ImageIcon legendIcon = new ImageIcon(imageForRule);
839    
840                                    final JLabel iconLabel = new JLabel(legendIcon);
841                                    hbox.setAlignmentX(0f);
842                                    hbox.add(iconLabel);
843                                    hbox.add(Box.createHorizontalStrut(3));
844    
845                                    // ****************************************************************************
846                                    // The labeltext is read from the SLD. Its either the title
847                                    // directly, or interpreted as OneLine Code
848                                    // ****************************************************************************
849                                    // final String rawText =
850                                    // rule.getDescription().getTitle().toString();
851                                    final String rawText = rule.getDescription().getTitle().toString();
852    
853                                    Translation labelT = new Translation();
854                                    labelT.fromOneLine(rawText);
855    
856                                    final JLabel classTitleLabel = new JLabel(labelT.toString());
857                                    hbox.add(classTitleLabel);
858                                    classTitleLabel.setLabelFor(iconLabel);
859    
860                                    box.add(hbox);
861    
862                            }
863                    }
864    
865                    return box;
866            }
867    
868    
869            /**
870             * Creates a
871             * @param styledGrid
872             * @param iconHeight
873             * @param iconWidth
874             * @return
875             */
876            public static Box createLegendPanel(StyledRasterInterface<?> styledGrid, int iconWidth, int iconHeight) {
877                    throw new RuntimeException("Not yet...");
878            }
879    
880    
881    }

Legend:
Removed from v.127  
changed lines
  Added in v.397

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26