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

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26