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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26