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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1039 - (hide annotations)
Wed Sep 22 10:54:14 2010 UTC (14 years, 5 months ago) by mojays
File size: 46671 byte(s)
BugFix for AttributeMetadata-Parsing: Do not use String.valueOf(String) because for NULL this method does return "null" and not NULL
1 alfonx 244 /*******************************************************************************
2     * Copyright (c) 2009 Martin O. J. Schmitz.
3     *
4     * This file is part of the SCHMITZM library - a collection of utility
5 alfonx 256 * classes based on Java 1.6, focusing (not only) on Java Swing
6 alfonx 244 * and the Geotools library.
7     *
8     * The SCHMITZM project is hosted at:
9     * http://wald.intevation.org/projects/schmitzm/
10     *
11     * This program is free software; you can redistribute it and/or
12     * modify it under the terms of the GNU Lesser General Public License
13     * as published by the Free Software Foundation; either version 3
14     * of the License, or (at your option) any later version.
15     *
16     * This program is distributed in the hope that it will be useful,
17     * but WITHOUT ANY WARRANTY; without even the implied warranty of
18     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19     * GNU General Public License for more details.
20     *
21     * 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     * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24     * or try this link: http://www.gnu.org/licenses/lgpl.html
25     *
26     * Contributors:
27     * Martin O. J. Schmitz - initial API and implementation
28 alfonx 862 * Stefan A. Tzeggai - additional utility classes
29 alfonx 244 ******************************************************************************/
30     package skrueger.geotools;
31    
32 alfonx 397 import java.awt.Color;
33     import java.awt.Dimension;
34 alfonx 400 import java.awt.Graphics2D;
35     import java.awt.Rectangle;
36     import java.awt.geom.AffineTransform;
37 alfonx 397 import java.awt.image.BufferedImage;
38 alfonx 403 import java.awt.image.ColorModel;
39 alfonx 405 import java.awt.image.ComponentColorModel;
40     import java.awt.image.DataBuffer;
41 alfonx 244 import java.io.File;
42     import java.io.FileNotFoundException;
43     import java.io.FileWriter;
44     import java.net.URL;
45     import java.text.DecimalFormat;
46 alfonx 607 import java.util.ArrayList;
47 alfonx 244 import java.util.List;
48     import java.util.Map;
49 alfonx 769 import java.util.Set;
50 alfonx 244
51 alfonx 403 import javax.swing.BorderFactory;
52 alfonx 397 import javax.swing.ImageIcon;
53 alfonx 516 import javax.swing.JComponent;
54 alfonx 397 import javax.swing.JLabel;
55    
56 alfonx 516 import net.miginfocom.swing.MigLayout;
57    
58 alfonx 244 import org.apache.log4j.Logger;
59 alfonx 403 import org.geotools.coverage.grid.GeneralGridEnvelope;
60 alfonx 244 import org.geotools.coverage.grid.GridCoverage2D;
61 alfonx 403 import org.geotools.coverage.grid.GridGeometry2D;
62 alfonx 244 import org.geotools.coverage.grid.io.AbstractGridCoverage2DReader;
63 alfonx 405 import org.geotools.coverage.grid.io.AbstractGridFormat;
64 alfonx 244 import org.geotools.feature.FeatureCollection;
65 alfonx 464 import org.geotools.feature.NameImpl;
66 alfonx 403 import org.geotools.geometry.jts.ReferencedEnvelope;
67 alfonx 244 import org.geotools.map.DefaultMapLayer;
68     import org.geotools.map.MapLayer;
69 alfonx 405 import org.geotools.parameter.Parameter;
70 alfonx 400 import org.geotools.renderer.lite.gridcoverage2d.GridCoverageRenderer;
71 alfonx 244 import org.geotools.styling.ColorMap;
72     import org.geotools.styling.ColorMapEntry;
73 alfonx 397 import org.geotools.styling.FeatureTypeStyle;
74 alfonx 244 import org.geotools.styling.RasterSymbolizer;
75 alfonx 397 import org.geotools.styling.Rule;
76 alfonx 244 import org.geotools.styling.Style;
77     import org.jdom.Document;
78     import org.jdom.Element;
79     import org.jdom.input.SAXBuilder;
80     import org.jdom.output.XMLOutputter;
81 alfonx 420 import org.opengis.feature.simple.SimpleFeature;
82 alfonx 397 import org.opengis.feature.simple.SimpleFeatureType;
83 alfonx 607 import org.opengis.feature.type.AttributeDescriptor;
84     import org.opengis.feature.type.GeometryDescriptor;
85 alfonx 464 import org.opengis.feature.type.Name;
86 alfonx 403 import org.opengis.parameter.GeneralParameterValue;
87 alfonx 244
88 alfonx 400 import schmitzm.geotools.JTSUtil;
89 alfonx 420 import schmitzm.geotools.feature.FeatureUtil;
90 alfonx 244 import schmitzm.geotools.styling.StylingUtil;
91     import schmitzm.io.IOUtil;
92     import schmitzm.lang.LangUtil;
93 alfonx 516 import schmitzm.swing.JPanel;
94 alfonx 244 import schmitzm.swing.SwingUtil;
95 alfonx 788 import skrueger.AttributeMetadataImpl;
96 alfonx 772 import skrueger.AttributeMetadataInterface;
97 alfonx 244 import skrueger.RasterLegendData;
98     import skrueger.i8n.Translation;
99    
100     /**
101     * This class provides static helper methods for dealing with
102     * {@link StyledLayerInterface} stuff.
103 alfonx 400 *
104     * @author <a href="mailto:[email protected]">Martin Schmitz</a>
105     * (University of Bonn/Germany)
106 alfonx 244 * @version 1.0
107     */
108     public class StyledLayerUtil {
109 alfonx 400 private static final Logger LOGGER = Logger.getLogger(StyledLayerUtil.class
110     .getName());
111     private static final SAXBuilder SAX_BUILDER = new SAXBuilder();
112     private static final XMLOutputter XML_OUTPUTTER = new XMLOutputter();
113 alfonx 244
114 alfonx 400 /** URL for Atlas XML schema */
115     public static final String AMLURI = "http://www.wikisquare.de/AtlasML";
116     /** Name of the XML Element for the attribute meta data map */
117     public static final String ELEM_NAME_AMD = "attributeMetaData";
118     /** Name of the XML Element for the raster legend data */
119     public static final String ELEM_NAME_RLD = "rasterLegendData";
120     /** Name of the XML Element for an attribute meta data map entry */
121     public static final String ELEM_NAME_ATTRIBUTE = "dataAttribute";
122     /** Name of the XML Element for an raster legend data entry */
123     public static final String ELEM_NAME_RASTERLEGEND = "rasterLegendItem";
124     /** Name of the XML Element for a translation */
125     public static final String ELEM_NAME_TRANSLATION = "translation";
126 alfonx 244
127 alfonx 400 /**
128     * Creates a Geotools {@link MapLayer} from an object. If the object is a
129     * {@link StyledLayerInterface} then its sytle is used. In case of direct
130     * Geotools objects ({@link GridCoverage2D},
131     * {@link AbstractGridCoverage2DReader}, {@link FeatureCollection}) a
132     * default style is generated.
133     *
134     * @param object
135     * an Object
136     * @exception Exception
137     * if {@code null} is given as object or an error occurs
138     * during layer creation
139     */
140 alfonx 516 public static MapLayer createMapLayer(final Object object) throws Exception {
141 alfonx 400 return createMapLayer(object, null);
142     }
143 alfonx 244
144 alfonx 400 /**
145     * Creates a Geotools {@link MapLayer} from an object. If the object is a
146     * {@link StyledLayerInterface} then its sytle is used. In case of direct
147     * Geotools objects ({@link GridCoverage2D},
148     * {@link AbstractGridCoverage2DReader}, {@link FeatureCollection}) a
149     * default style is generated.
150     *
151     * @param object
152     * an Object
153     * @param forcedStyle
154     * (SLD-)Style to force for the object
155     * @exception Exception
156     * if {@code null} is given as object or an error occurs
157     * during layer creation
158     */
159 alfonx 516 public static MapLayer createMapLayer(Object object, final Style forcedStyle)
160 alfonx 400 throws Exception {
161     MapLayer layer = null;
162     Style style = null;
163     if (object instanceof StyledLayerInterface) {
164     style = ((StyledLayerInterface<?>) object).getStyle();
165     object = ((StyledLayerInterface<?>) object).getGeoObject();
166     }
167     if (forcedStyle != null)
168     style = forcedStyle;
169     if (style == null)
170     style = StylingUtil.createDefaultStyle(object);
171 alfonx 244
172 alfonx 400 if (object instanceof GridCoverage2D)
173     layer = new DefaultMapLayer((GridCoverage2D) object, style);
174     if (object instanceof AbstractGridCoverage2DReader)
175     layer = new DefaultMapLayer((AbstractGridCoverage2DReader) object,
176     style);
177     if (object instanceof FeatureCollection)
178     layer = new DefaultMapLayer((FeatureCollection) object, style);
179 alfonx 244
180 alfonx 400 if (layer == null)
181     throw new Exception("Can not create MapLayer from "
182     + (object == null ? "null" : object.getClass()));
183 alfonx 244
184 alfonx 400 return layer;
185     }
186 alfonx 244
187 alfonx 400 /**
188     * Creates an default instance of {@link StyledLayerInterface} for a
189     * Geotools object ({@link GridCoverage2D}, {@link FeatureCollection}) with
190     * a default style.
191     *
192     * @param object
193     * an Object
194     * @param title
195     * title for the object
196     * @exception UnsupportedOperationException
197     * if {@code null} is given as object or an error occurs
198     * during creation
199     */
200 alfonx 516 public static StyledLayerInterface<?> createStyledLayer(
201     final Object object, final String title) {
202 alfonx 400 return createStyledLayer(object, title, null);
203     }
204 alfonx 244
205 alfonx 400 /**
206     * Creates an default instance of {@link StyledLayerInterface} for a
207     * Geotools object ({@link GridCoverage2D}, {@link FeatureCollection}) with
208     * a given style.
209     *
210     * @param object
211     * an Object
212     * @param title
213     * title for the object
214     * @param style
215     * style and meta data for the object
216     * @exception UnsupportedOperationException
217     * if {@code null} is given as object or an error occurs
218     * during creation
219     */
220 alfonx 516 public static StyledLayerInterface<?> createStyledLayer(
221     final Object object, final String title,
222     final StyledLayerStyle style) {
223 alfonx 400 StyledLayerInterface<?> styledLayer = null;
224 alfonx 244
225 alfonx 516 final String id = (title != null) ? title : "defaultID";
226 alfonx 244
227 alfonx 400 if (object instanceof GridCoverage2D)
228     styledLayer = new StyledGridCoverage((GridCoverage2D) object, id,
229     title, style);
230     else if (object instanceof AbstractGridCoverage2DReader)
231     styledLayer = new StyledGridCoverageReader(
232     (AbstractGridCoverage2DReader) object, id, title, style);
233     else if (object instanceof FeatureCollection)
234     styledLayer = new StyledFeatureCollection(
235     (FeatureCollection) object, id, title, style);
236 alfonx 244
237 alfonx 400 if (styledLayer == null)
238     throw new UnsupportedOperationException(
239     "Can not create StyledLayerInterface object from "
240     + (object == null ? "null" : object.getClass()));
241 alfonx 244
242 alfonx 400 return styledLayer;
243     }
244 alfonx 244
245 alfonx 400 /**
246     * Return only the visible or invisible entries of an AttributeMetaData-Map.
247     *
248     * @param amdMap
249     * AttributeMetaData-Map
250     * @param visible
251     * indicated whether the visible or invisible entries are
252     * returned
253 alfonx 607 *
254     * TODO replace with
255     * {@link AttributeMetadataMap#sortedValuesVisibleOnly()}
256 alfonx 400 */
257 alfonx 772 public static AttributeMetadataMap<? extends AttributeMetadataInterface > getVisibleAttributeMetaData(
258     final AttributeMetadataMap<? extends AttributeMetadataInterface> amdMap,
259 alfonx 769 final boolean visible) {
260 alfonx 516
261 alfonx 772 final AttributeMetadataMap<AttributeMetadataInterface> filteredMap = (AttributeMetadataMap<AttributeMetadataInterface>) amdMap.clone();
262 alfonx 769 if (filteredMap.size() > 0 ) {
263     filteredMap.clear(); // Just in case the close copies the contents
264     }
265    
266 alfonx 772 for (final AttributeMetadataInterface amd : amdMap.values())
267 alfonx 464 if (amd.isVisible() == visible)
268     filteredMap.put(amd.getName(), amd);
269 alfonx 244
270 alfonx 400 return filteredMap;
271     }
272 alfonx 244
273 alfonx 400 /**
274 alfonx 769 * Parses a {@link AttributeMetadataImpl} object from an JDOM-
275     * {@link Element}. This method works like {@link
276 alfonx 400 * AMLImport#parseDataAttribute(org.w3c.dom.Node}, but for JDOM.
277     *
278 alfonx 534 * TODO 20.11.2009, SK: There are some new attribute weight, functiona,
279     * functionX and nodata in AttributeMetaData that should be parsed/exported
280     * too. but this method is only used by ISDSS, which is not supporting that
281     * stuff anyways.
282     *
283 alfonx 400 * @param element
284     * {@link Element} to parse
285     */
286 alfonx 769 public static AttributeMetadataImpl parseAttributeMetaData(
287     final Element element) {
288 mojays 1039 final String namespace = element.getAttributeValue("namespace");
289     final String localname = element.getAttributeValue("localname");
290 alfonx 770 final NameImpl aName = new NameImpl(namespace, localname);
291 alfonx 400 final Boolean visible = Boolean.valueOf(element
292     .getAttributeValue("visible"));
293     final String unit = element.getAttributeValue("unit");
294 alfonx 244
295 alfonx 400 Translation name = new Translation();
296     Translation desc = new Translation();
297     for (final Element childElement : (List<Element>) element.getChildren()) {
298     if (childElement.getName() == null)
299     continue;
300 alfonx 244
301 alfonx 400 if (childElement.getName().equals("name"))
302     name = parseTranslation(childElement);
303     else if (childElement.getName().equals("desc"))
304     desc = parseTranslation(childElement);
305     }
306 alfonx 769 return new AttributeMetadataImpl(aName, visible, name, desc, unit);
307 alfonx 400 }
308 alfonx 244
309 alfonx 400 /**
310 alfonx 769 * Parses a {@link AttributeMetadataImpl} map from an JDOM-{@link Element}
311     * with {@code <attribute>}-childs.
312 alfonx 400 *
313     * @param element
314     * {@link Element} to parse
315 alfonx 677 *
316 alfonx 769 * TODO Since GP 1.3 the {@link AttributeMetadataImpl} class has
317     * more attributes which are not used by Xulu/ISDSS. GP
318 alfonx 658 * exports/imports the AMD via AMLExporter and AMLImporter
319 alfonx 677 * classes. (SK, 3.2.2010) *
320 alfonx 400 */
321 alfonx 420 public static AttributeMetadataMap parseAttributeMetaDataMap(
322 alfonx 400 final Element element) {
323 alfonx 769 final AttributeMetadataMap metaData = new AttributeMetadataImplMap();
324 alfonx 516 final List<Element> attributesElements = element
325 alfonx 400 .getChildren(ELEM_NAME_ATTRIBUTE);
326 alfonx 516 for (final Element attibuteElement : attributesElements) {
327 alfonx 769 final AttributeMetadataImpl attrMetaData = parseAttributeMetaData(attibuteElement);
328 alfonx 464 metaData.put(attrMetaData.getName(), attrMetaData);
329 alfonx 400 }
330     return metaData;
331     }
332 alfonx 244
333 alfonx 400 /**
334 alfonx 769 * Loads a {@link AttributeMetadataImpl} object from an URL.
335 alfonx 400 *
336     * @param documentUrl
337     * {@link URL} to parse
338     * @see #parseAttributeMetaData(Element)
339     */
340 alfonx 420 public static AttributeMetadataMap loadAttributeMetaDataMap(
341 alfonx 400 final URL documentUrl) throws Exception {
342 alfonx 516 final Document document = SAX_BUILDER.build(documentUrl);
343 alfonx 400 return parseAttributeMetaDataMap(document.getRootElement());
344     }
345 alfonx 244
346 alfonx 400 /**
347 alfonx 769 * Creates an JDOM {@link Element} for the given
348     * {@link AttributeMetadataImpl} object.
349 alfonx 400 *
350     * @param amd
351     * meta data for one attribute
352 alfonx 658 *
353 alfonx 769 * TODO Since GP 1.3 the {@link AttributeMetadataImpl} class has
354     * more attributes which are not used by Xulu/ISDSS. GP
355 alfonx 658 * exports/imports the AMD via AMLExporter and AMLImporter
356     * classes. (SK, 3.2.2010)
357 alfonx 400 */
358     public static Element createAttributeMetaDataElement(
359 alfonx 772 final AttributeMetadataInterface amd) {
360 alfonx 400 final Element element = new Element(ELEM_NAME_ATTRIBUTE, AMLURI);
361 alfonx 516 element.setAttribute("namespace", String.valueOf(amd.getName()
362     .getNamespaceURI()));
363 alfonx 464 element.setAttribute("localname", String.valueOf(amd.getLocalName()));
364 alfonx 400 element.setAttribute("visible", String.valueOf(amd.isVisible()));
365     element.setAttribute("unit", amd.getUnit());
366     // Creating a aml:name tag...
367     element.addContent(createTranslationElement("name", amd.getTitle()));
368     // Creating a aml:desc tag...
369     element.addContent(createTranslationElement("desc", amd.getDesc()));
370     return element;
371     }
372 alfonx 244
373 alfonx 400 /**
374 alfonx 769 * Creates an JDOM {@link Element} for the given
375     * {@link AttributeMetadataImpl} map.
376 alfonx 400 *
377     * @param amdMap
378     * map of attribute meta data
379     */
380     public static Element createAttributeMetaDataMapElement(
381 alfonx 772 final AttributeMetadataMap<? extends AttributeMetadataInterface> amdMap) {
382 alfonx 400 final Element element = new Element(ELEM_NAME_AMD, AMLURI);
383 alfonx 772 for (final AttributeMetadataInterface amd : amdMap.values())
384 alfonx 400 element.addContent(createAttributeMetaDataElement(amd));
385     return element;
386     }
387 alfonx 244
388 alfonx 400 /**
389 alfonx 769 * Saves a {@link AttributeMetadataImpl AttributeMetaData-Map} to an URL.
390 alfonx 400 *
391     * @param amdMap
392 alfonx 769 * map of {@link AttributeMetadataImpl}
393 alfonx 400 * @param documentUrl
394     * {@link URL} to store the XML
395     */
396     public static void saveAttributeMetaDataMap(
397 alfonx 420 final AttributeMetadataMap amdMap, final URL documentUrl)
398 alfonx 400 throws Exception {
399     // Create XML-Document
400     final FileWriter out = new FileWriter(new File(documentUrl.toURI()));
401     XML_OUTPUTTER.output(createAttributeMetaDataMapElement(amdMap), out);
402     out.flush();
403     out.close();
404     }
405 alfonx 244
406 alfonx 400 /**
407     * Parses a {@link RasterLegendData} object from an JDOM-{@link Element}.
408     * This method works like {@link
409     * AMLImport#parseRasterLegendData(org.w3c.dom.Node}, but for JDOM.
410     *
411     * @param element
412     * {@link Element} to parse
413     */
414 alfonx 516 public static RasterLegendData parseRasterLegendData(final Element element) {
415 alfonx 244
416 alfonx 400 final boolean paintGaps = Boolean.valueOf(element
417     .getAttributeValue("paintGaps"));
418 alfonx 244
419 alfonx 516 final RasterLegendData rld = new RasterLegendData(paintGaps);
420 alfonx 244
421 alfonx 516 for (final Element childElement : (List<Element>) element.getChildren()) {
422 alfonx 400 final String name = childElement.getName();
423     // Cancel if it's an attribute
424     if (childElement.getChildren().size() == 0)
425     continue;
426 alfonx 244
427 alfonx 400 if (name.equals(ELEM_NAME_RASTERLEGEND)) {
428     final String valueAttr = childElement
429     .getAttributeValue("value");
430     if (valueAttr == null)
431     throw new UnsupportedOperationException(
432     "Attribute 'value' missing for definition of <"
433     + ELEM_NAME_RASTERLEGEND + ">");
434     final double value = Double.valueOf(valueAttr);
435 alfonx 244
436 alfonx 400 // first and only item should be the label
437     final Element labelElement = childElement.getChild("label");
438     // id label element is missing, the translation is searched
439     // directly
440     // as childs of the rasterLegendItem element
441 alfonx 516 final Translation label = parseTranslation(labelElement != null ? labelElement
442 alfonx 400 : childElement);
443     rld.put(value, label);
444     }
445     }
446 alfonx 244
447 alfonx 400 return rld;
448     }
449 alfonx 244
450 alfonx 400 /**
451     * Loads a {@link RasterLegendData} object from an URL.
452     *
453     * @param documentUrl
454     * {@link URL} to parse
455     * @see #parseAttributeMetaData(Element)
456     */
457     public static RasterLegendData loadRasterLegendData(final URL documentUrl)
458     throws Exception {
459 alfonx 516 final Document document = SAX_BUILDER.build(documentUrl);
460 alfonx 400 return parseRasterLegendData(document.getRootElement());
461     }
462 alfonx 244
463 alfonx 400 /**
464     * Creates an JDOM {@link Element} for the given {@link RasterLegendData}
465     * map.
466     *
467     * @param rld
468     * raster legend data
469     */
470     public static Element createRasterLegendDataElement(
471     final RasterLegendData rld) {
472     final Element element = new Element(ELEM_NAME_RLD, AMLURI);
473     element.setAttribute("paintGaps", rld.isPaintGaps().toString());
474 alfonx 516 for (final Double key : rld.getSortedKeys()) {
475     final Element item = new Element(ELEM_NAME_RASTERLEGEND, AMLURI);
476 alfonx 400 item.setAttribute("value", key.toString());
477     item.addContent(createTranslationElement("label", rld.get(key)));
478     element.addContent(item);
479     }
480     return element;
481     }
482 alfonx 244
483 alfonx 400 /**
484     * Creates {@link RasterLegendData} from a {@link ColorMap}.
485     *
486     * @param colorMap
487     * a color map
488     * @param paintGaps
489     * indicated whether gaps are painted between the legend items
490     * @param digits
491     * number of digits the grid value classes (and legend) are
492     * rounded to (null means no round; >= 0 means digits after
493     * comma; < 0 means digits before comma)
494     */
495 alfonx 516 public static RasterLegendData generateRasterLegendData(
496     final ColorMap colorMap, final boolean paintGaps,
497     final Integer digits) {
498     final DecimalFormat decFormat = digits != null ? new DecimalFormat(
499     SwingUtil.getNumberFormatPattern(digits)) : null;
500     final RasterLegendData rld = new RasterLegendData(paintGaps);
501     for (final ColorMapEntry cme : colorMap.getColorMapEntries()) {
502     final double value = StylingUtil.getQuantityFromColorMapEntry(cme);
503 alfonx 400 String label = cme.getLabel();
504     // if no label is set (e.g. quantitative style),
505     // use the value as label
506     if (label == null || label.equals(""))
507     if (digits == null)
508     label = String.valueOf(value);
509     else
510     label = decFormat.format(LangUtil.round(value, digits));
511     rld.put(value, new Translation(" " + label));
512     }
513     return rld;
514     }
515 alfonx 244
516 alfonx 400 /**
517     * Creates {@link RasterLegendData} from the {@link ColorMap} of a style.
518     *
519     * @param style
520     * a raster style (must contain a {@link RasterSymbolizer})
521     * @param paintGaps
522     * indicated whether gaps are painted between the legend items
523     * @param digits
524     * number of digits the grid value classes (and legend) are
525     * rounded to (null means no round; >= 0 means digits after
526     * comma; < 0 means digits before comma)
527     */
528 alfonx 516 public static RasterLegendData generateRasterLegendData(final Style style,
529     final boolean paintGaps, final Integer digits) {
530     final ColorMap colorMap = StylingUtil.getColorMapFromStyle(style);
531 alfonx 400 if (colorMap == null)
532     throw new IllegalArgumentException(
533     "Color map can not be determined from style!");
534     return generateRasterLegendData(colorMap, paintGaps, digits);
535     }
536 alfonx 244
537 alfonx 400 /**
538     * Saves a {@link RasterLegendData} to an URL.
539     *
540     * @param rld
541     * raster legend data
542     * @param documentUrl
543     * {@link URL} to store the XML
544     */
545     public static void saveRasterLegendData(final RasterLegendData rld,
546     final URL documentUrl) throws Exception {
547     // Create XML-Document
548     final FileWriter out = new FileWriter(new File(documentUrl.toURI()));
549     XML_OUTPUTTER.output(createRasterLegendDataElement(rld), out);
550     out.flush();
551     out.close();
552     }
553 alfonx 244
554 alfonx 400 /**
555     * Parses a {@link Translation} object from an JDOM-{@link Element}. This
556     * method works like {@link AMLImport#parseTranslation(org.w3c.dom.Node},
557     * but for JDOM.
558     *
559     * @param element
560     * {@link Element} to parse
561     */
562     public final static Translation parseTranslation(final Element element) {
563 alfonx 516 final Translation trans = new Translation();
564 alfonx 244
565 alfonx 400 if (element == null)
566     return trans;
567 alfonx 244
568 alfonx 400 for (final Element translationElement : (List<Element>) element
569     .getChildren()) {
570     final String name = translationElement.getName();
571     if (name == null)
572     continue;
573 alfonx 244
574 alfonx 400 // lang attribute
575     String lang = translationElement.getAttributeValue("lang");
576     // set the default, if no language code is set
577     if (lang == null)
578     lang = Translation.DEFAULT_KEY;
579 alfonx 244
580 alfonx 400 final String translationText = translationElement.getValue();
581     if (translationText == null)
582     trans.put(lang, "");
583     else
584     trans.put(lang, translationText);
585     }
586 alfonx 244
587 alfonx 400 // if no <translation> is given, the value of the node should
588     // be used as a default translation
589     if (trans.size() == 0)
590     trans.put(Translation.DEFAULT_KEY, element.getValue());
591     // trans = new Translation(
592     // ((List<Element>)element.getChildren()).get(0).getValue() );
593 alfonx 244
594 alfonx 400 return trans;
595     }
596 alfonx 244
597 alfonx 400 /**
598     * Creates an JDOM {@link Element} for the given {@link Translation}.
599     *
600     * @param tagname
601     * Name of the Element
602     * @param translation
603     * Translation to store in the Element
604     */
605 alfonx 516 public final static Element createTranslationElement(final String tagname,
606     final Translation translation) {
607     final Element element = new Element(tagname, AMLURI);
608 alfonx 400 if (translation == null)
609     throw new UnsupportedOperationException(
610     "Translation element can not be created from null!");
611 alfonx 244
612 alfonx 400 // If only a default translation is set, the <translation
613     // lang="..">..</tranlation>
614     // part is not used
615     if (translation.keySet().size() == 1
616     && translation.get(Translation.DEFAULT_KEY) != null) {
617     element.addContent(translation.get(Translation.DEFAULT_KEY));
618     return element;
619     }
620 alfonx 244
621 alfonx 400 // add a <translation lang="..">..</tranlation> part to the element for
622     // all languages
623 alfonx 516 for (final String lang : translation.keySet()) {
624     final Element translationElement = new Element(
625     ELEM_NAME_TRANSLATION, AMLURI);
626 alfonx 400 translationElement.setAttribute("lang", lang);
627     String translationString = translation.get(lang);
628     if (translationString == null)
629     translationString = "";
630     translationElement.addContent(translationString);
631     element.addContent(translationElement);
632     }
633 alfonx 244
634 alfonx 400 return element;
635     }
636 alfonx 244
637 alfonx 400 /**
638     * Sets a style to {@link StyledLayerInterface}.
639     *
640     * @param styledObject
641     * a styled object
642     * @param style
643     * a Style
644     */
645 alfonx 516 public static void setStyledLayerStyle(
646     final StyledLayerInterface styledObject,
647     final StyledLayerStyle<?> style) {
648 alfonx 400 // set SLD style
649     styledObject.setStyle(style.getGeoObjectStyle());
650     // set meta data
651     if (styledObject instanceof StyledGridCoverageInterface
652     && (style.getMetaData() instanceof RasterLegendData || style
653     .getMetaData() == null)) {
654 alfonx 516 final RasterLegendData sourceRld = (RasterLegendData) style
655     .getMetaData();
656     final RasterLegendData destRld = ((StyledGridCoverageInterface) styledObject)
657 alfonx 400 .getLegendMetaData();
658     if (destRld != null && sourceRld != null) {
659     destRld.setPaintGaps(sourceRld.isPaintGaps());
660     destRld.clear();
661     destRld.putAll(sourceRld);
662     }
663     return;
664     }
665     if (styledObject instanceof StyledFeatureCollectionInterface
666     && (style.getMetaData() instanceof Map || style.getMetaData() == null)) {
667 alfonx 516 final AttributeMetadataMap sourceAmd = (AttributeMetadataMap) style
668 alfonx 400 .getMetaData();
669 alfonx 516 final AttributeMetadataMap destAmd = ((StyledFeatureCollectionInterface) styledObject)
670 alfonx 400 .getAttributeMetaDataMap();
671     if (destAmd != null && sourceAmd != null) {
672     destAmd.clear();
673     destAmd.putAll(sourceAmd);
674     }
675     return;
676     }
677 alfonx 244
678 alfonx 400 throw new UnsupportedOperationException(
679     "Style is not compatible to object: "
680     + (style.getMetaData() == null ? null : style
681     .getMetaData().getClass().getSimpleName())
682     + " <-> "
683     + (styledObject == null ? null : styledObject
684     .getClass().getSimpleName()));
685     }
686 alfonx 244
687 alfonx 400 /**
688     * Returns the style a {@link StyledLayerInterface} as a
689     * {@link StyledLayerStyle}.
690     *
691     * @param styledObject
692     * a styled object
693     * @return {@code StyledLayerStyle<RasterLegendData>} for
694     * {@link StyledGridCoverageInterface} or {@code
695     * StyledLayerStyle<Map<Integer,AttributeMetaData>>} for
696     * {@link StyledFeatureCollectionInterface}
697     */
698     public static StyledLayerStyle<?> getStyledLayerStyle(
699 alfonx 516 final StyledLayerInterface styledObject) {
700 alfonx 400 if (styledObject instanceof StyledGridCoverageInterface)
701     return getStyledLayerStyle((StyledGridCoverageInterface) styledObject);
702     if (styledObject instanceof StyledFeatureCollectionInterface)
703     return getStyledLayerStyle((StyledFeatureCollectionInterface) styledObject);
704     throw new UnsupportedOperationException(
705     "Unknown type of StyledLayerInterface: "
706     + (styledObject == null ? null : styledObject
707     .getClass().getSimpleName()));
708     }
709 alfonx 244
710 alfonx 400 /**
711     * Returns the style and raster meta data of a
712     * {@link StyledGridCoverageInterface} as a {@link StyledLayerStyle}.
713     *
714     * @param styledGC
715     * a styled grid coverage
716     */
717     public static StyledLayerStyle<RasterLegendData> getStyledLayerStyle(
718 alfonx 516 final StyledGridCoverageInterface styledGC) {
719 alfonx 400 return new StyledLayerStyle<RasterLegendData>(styledGC.getStyle(),
720     styledGC.getLegendMetaData());
721     }
722 alfonx 244
723 alfonx 400 /**
724     * Returns the style and attribute meta data of a
725     * {@link StyledFeatureCollectionInterface} as a {@link StyledLayerStyle}.
726     *
727     * @param styledFC
728     * a styled feature collection
729     */
730 alfonx 464 public static StyledLayerStyle<AttributeMetadataMap> getStyledLayerStyle(
731 alfonx 516 final StyledFeatureCollectionInterface styledFC) {
732     return new StyledLayerStyle<AttributeMetadataMap>(styledFC.getStyle(),
733     styledFC.getAttributeMetaDataMap());
734 alfonx 400 }
735 alfonx 244
736 alfonx 400 /**
737     * Loads a {@linkplain Style SLD-Style} and {@linkplain RasterLegendData
738     * Raster-LegendData} for a given geo-object (raster) source. The SLD file
739     * must be present. A missing raster legend-data file is tolerated.
740     *
741     * @param geoObjectURL
742     * URL of the (already read) raster object
743     * @param sldExt
744     * file extention for the SLD file
745     * @param rldExt
746     * file extention for the raster legend-data file
747     * @return {@code null} in case of any error
748     */
749     public static StyledLayerStyle<RasterLegendData> loadStyledRasterStyle(
750 alfonx 516 final URL geoObjectURL, final String sldExt, final String rldExt) {
751 alfonx 400 RasterLegendData metaData = null;
752     Style sldStyle = null;
753     try {
754 alfonx 516 final Style[] styles = StylingUtil.loadSLD(IOUtil.changeUrlExt(
755 alfonx 400 geoObjectURL, sldExt));
756     // SLD must be present
757     if (styles == null || styles.length == 0)
758     return null;
759     sldStyle = styles[0];
760 alfonx 516 } catch (final Exception err) {
761 alfonx 400 // SLD must be present
762     LangUtil.logDebugError(LOGGER, err);
763     return null;
764     }
765 alfonx 244
766 alfonx 400 try {
767     metaData = StyledLayerUtil.loadRasterLegendData(IOUtil
768     .changeUrlExt(geoObjectURL, rldExt));
769 alfonx 516 } catch (final FileNotFoundException err) {
770 alfonx 400 // ignore missing raster legend data
771 alfonx 516 } catch (final Exception err) {
772 alfonx 400 // any other error during legend data creation leads to error
773     LangUtil.logDebugError(LOGGER, err);
774     return null;
775     }
776     return new StyledLayerStyle<RasterLegendData>(sldStyle, metaData);
777     }
778 alfonx 244
779 alfonx 400 /**
780     * Loads a {@linkplain Style SLD-Style} from a {@code .sld} file and
781     * {@linkplain RasterLegendData Raster-LegendData} from a {@code .rld} file
782     * for a given geo-object (raster) source. The SLD file must be present. A
783     * missing raster legend-data file is tolerated.
784     *
785     * @param geoObjectURL
786     * URL of the (already read) raster object
787     * @param sldExt
788     * file extention for the SLD file
789     * @param rldExt
790     * file extention for the raster legend-data file
791     * @return {@code null} in case of any error
792     */
793     public static StyledLayerStyle<RasterLegendData> loadStyledRasterStyle(
794 alfonx 516 final URL geoObjectURL) {
795 alfonx 400 return loadStyledRasterStyle(geoObjectURL, "sld", "rld");
796     }
797 alfonx 244
798 alfonx 400 /**
799 alfonx 769 * Loads a {@linkplain Style SLD-Style} and a
800     * {@linkplain AttributeMetadataImpl AttributeMetaData-Map} for a given
801     * geo-object (feature) source. The SLD file must be present. A missing
802     * attribute meta-data file is tolerated.
803 alfonx 400 *
804     * @param geoObjectURL
805     * URL of the (already read) feature object
806     * @param sldExt
807     * file extention for the SLD file
808     * @param rldExt
809     * file extention for the raster legend-data file
810     * @return {@code null} in case of any error
811     */
812 alfonx 464 public static StyledLayerStyle<AttributeMetadataMap> loadStyledFeatureStyle(
813 alfonx 516 final URL geoObjectURL, final String sldExt, final String rldExt) {
814 alfonx 464 AttributeMetadataMap metaData = null;
815 alfonx 400 Style sldStyle = null;
816     try {
817 alfonx 516 final Style[] styles = StylingUtil.loadSLD(IOUtil.changeUrlExt(
818 alfonx 400 geoObjectURL, sldExt));
819     // SLD must be present
820     if (styles == null || styles.length == 0)
821     return null;
822     sldStyle = styles[0];
823 alfonx 516 } catch (final Exception err) {
824 alfonx 400 // SLD must be present
825     LangUtil.logDebugError(LOGGER, err);
826     return null;
827     }
828 alfonx 244
829 alfonx 400 try {
830     metaData = StyledLayerUtil.loadAttributeMetaDataMap(IOUtil
831     .changeUrlExt(geoObjectURL, rldExt));
832 alfonx 516 } catch (final FileNotFoundException err) {
833 alfonx 400 // ignore missing attribute meta data
834 alfonx 516 } catch (final Exception err) {
835 alfonx 400 // any other error during meta data creation leads to error
836     LangUtil.logDebugError(LOGGER, err);
837     return null;
838     }
839 alfonx 244
840 alfonx 516 return new StyledLayerStyle<AttributeMetadataMap>(sldStyle, metaData);
841 alfonx 400 }
842 alfonx 244
843 alfonx 400 /**
844     * Loads a {@linkplain Style SLD-Style} from a {@code .sld} file and
845 alfonx 769 * {@linkplain AttributeMetadataImpl AttributeMetaData-Map} from a {@code
846     * .amd} file for a given geo-object (feature) source. The SLD file must be
847 alfonx 400 * present. A missing attribute meta-data file is tolerated.
848     *
849     * @param geoObjectURL
850     * URL of the (already read) feature object
851     * @param sldExt
852     * file extention for the SLD file
853     * @param rldExt
854     * file extention for the raster legend-data file
855     * @return {@code null} in case of any error
856     */
857 alfonx 464 public static StyledLayerStyle<AttributeMetadataMap> loadStyledFeatureStyle(
858 alfonx 516 final URL geoObjectURL) {
859 alfonx 400 return loadStyledFeatureStyle(geoObjectURL, "sld", "amd");
860     }
861 alfonx 244
862 alfonx 400 /**
863     * Stores a {@linkplain Style SLD-Style} and {@linkplain RasterLegendData
864     * Raster-LegendData} for a given geo-object (raster) source.
865     *
866     * @param style
867     * style to save
868     * @param geoObjectURL
869     * URL of the raster object
870     * @param sldExt
871     * file extention for the SLD file
872     * @param mdExt
873     * file extention for the meta-data file
874     */
875 alfonx 516 public static <T> void saveStyledLayerStyle(
876     final StyledLayerStyle<T> style, final URL geoObjectURL,
877     final String sldExt, final String mdExt) throws Exception {
878 alfonx 400 // Store the SLD
879 alfonx 516 final Style sldStyle = style.getGeoObjectStyle();
880 alfonx 400 if (sldStyle != null) {
881     StylingUtil.saveStyleToSLD(sldStyle, IOUtil.changeFileExt(new File(
882     geoObjectURL.toURI()), sldExt));
883     }
884 alfonx 244
885 alfonx 400 // Store the meta data
886 alfonx 516 final T metaData = style.getMetaData();
887 alfonx 400 if (metaData != null) {
888     if (metaData instanceof RasterLegendData) {
889     saveRasterLegendData((RasterLegendData) metaData, IOUtil
890     .changeUrlExt(geoObjectURL, mdExt));
891     // } else if ( metaData instanceof
892     // Map<Integer,AttributeMetaData> ) { // LEIDER NICHT
893     // KOMPILIERBAR!!
894     } else if (metaData instanceof Map) {
895 alfonx 516 saveAttributeMetaDataMap((AttributeMetadataMap) metaData,
896     IOUtil.changeUrlExt(geoObjectURL, mdExt));
897 alfonx 400 } else
898     throw new UnsupportedOperationException(
899     "Export for meta data not yet supported: "
900     + metaData.getClass().getSimpleName());
901     }
902     }
903 alfonx 244
904 alfonx 400 /**
905     * Stores the {@linkplain Style SLD-Style} to a {@code .sld} file and the
906 alfonx 769 * meta data ({@link RasterLegendData} or {@link AttributeMetadataImpl}) to
907     * a {@code .rld} or {@code .amd} file. for a given geo-object source.
908 alfonx 400 *
909     * @param style
910     * style to save
911     * @param geoObjectURL
912     * URL of the (already read) raster object
913     */
914 alfonx 516 public static void saveStyledLayerStyle(final StyledLayerStyle<?> style,
915     final URL geoObjectURL) throws Exception {
916 alfonx 400 if (style.getMetaData() instanceof RasterLegendData)
917     saveStyledLayerStyle(style, geoObjectURL, "sld", "rld");
918     else
919     saveStyledLayerStyle(style, geoObjectURL, "sld", "amd");
920     }
921 alfonx 244
922 alfonx 397 /**
923 alfonx 694 * *If appended to the name of a rule, this rule shall not be shown in the
924     * legend
925     */
926     public final static String HIDE_IN_LAYER_LEGEND_HINT = "HIDE_IN_LEGEND";
927    
928     /**
929 alfonx 516 * Creates a {@link JPanel} that shows a legend for a list of
930 alfonx 397 * {@link FeatureTypeStyle}s and a targeted featureType
931     *
932 alfonx 824 * @param style
933     * The Style to presented in this legend
934 alfonx 397 * @param featureType
935     * If this a legend for Point, Polygon or Line?
936     *
937     * @author <a href="mailto:[email protected]">Stefan Alfons
938 alfonx 888 * Tzeggai</a>
939 alfonx 397 */
940 alfonx 824 public static JPanel createLegendSwingPanel(Style style,
941 alfonx 516 final SimpleFeatureType featureType, final int iconWidth,
942     final int iconHeight) {
943 alfonx 397
944 alfonx 516 final List<FeatureTypeStyle> list = style.featureTypeStyles();
945 alfonx 397
946 alfonx 517 final JPanel panel = new JPanel(new MigLayout("wrap 2", "[]:3:[]"));
947 alfonx 397
948 alfonx 516 if (style == null) {
949     // No Style => no legend
950     return panel;
951     }
952 alfonx 397
953 alfonx 516 for (final FeatureTypeStyle ftStyle : list) {
954    
955 alfonx 397 // One child-node for every rule
956 alfonx 516 final List<Rule> rules = ftStyle.rules();
957     for (final Rule rule : rules) {
958 alfonx 397
959 alfonx 694 // Check if this RULE shall actually appear in the legend
960 alfonx 769 if (rule.getName() != null
961     && rule.getName().endsWith(HIDE_IN_LAYER_LEGEND_HINT))
962 alfonx 694 continue;
963    
964 alfonx 397 /**
965     * Let's not create a hbox for Rules that only contain
966     * TextSymbolizers
967     */
968     if (StylingUtil.getTextSymbolizers(rule.getSymbolizers())
969     .size() == rule.getSymbolizers().length)
970     continue;
971    
972     final BufferedImage imageForRule = LegendIconFeatureRenderer
973     .getInstance().createImageForRule(rule, featureType,
974 alfonx 516 new Dimension(iconWidth, iconHeight));
975 alfonx 397
976 alfonx 516 final ImageIcon legendIcon = new ImageIcon(imageForRule);
977 alfonx 397
978     final JLabel iconLabel = new JLabel(legendIcon);
979 alfonx 517 panel.add(iconLabel, "sgx1");
980     // hbox.setAlignmentX(0f);
981     // hbox.add(iconLabel);
982     // hbox.add(Box.createHorizontalStrut(3));
983 alfonx 397
984 alfonx 516 final Translation labelT = new Translation();
985 alfonx 409 labelT.fromOneLine(rule.getDescription().getTitle());
986 alfonx 397 final JLabel classTitleLabel = new JLabel(labelT.toString());
987 alfonx 517
988     panel.add(classTitleLabel, "sgx2");
989 alfonx 400 classTitleLabel.setLabelFor(iconLabel);
990 alfonx 397 }
991     }
992    
993 alfonx 516 return panel;
994 alfonx 397 }
995    
996 alfonx 824
997    
998    
999 alfonx 397 /**
1000 alfonx 516 * Creates a {@link JComponent} that contains a legend for a given
1001 alfonx 824 * {@link StyledRasterInterface} and a given {@link Style}.
1002 alfonx 400 *
1003 alfonx 516 * @param style
1004     * if <code>null</code>, the default {@link Style} is extracetd
1005     * from the {@link StyledRasterInterface}
1006 alfonx 397 */
1007 alfonx 824 public static JPanel createLegendSwingPanel(
1008 alfonx 516 final StyledRasterInterface<?> styledRaster, Style style,
1009     final int iconWidth, final int iconHeight) {
1010 alfonx 403
1011 alfonx 516 // If no style is given, we use the default style for this layer
1012     if (style == null)
1013     style = styledRaster.getStyle();
1014    
1015 alfonx 403 /**
1016     * Determine whether a Style is responsible for the coloring
1017     */
1018     ColorModel colorModel = null;
1019 alfonx 405 if (!isStyleable(styledRaster)
1020 alfonx 516 || (isStyleable(styledRaster) && style == null)) {
1021 alfonx 405 colorModel = getColorModel(styledRaster);
1022 alfonx 403 }
1023    
1024 alfonx 516 final RasterLegendData rasterLegendData = styledRaster
1025     .getLegendMetaData();
1026     final List<Double> legendRasterValues = rasterLegendData
1027     .getSortedKeys();
1028     final Map<Double, GridCoverage2D> sampleRasters = rasterLegendData
1029 alfonx 400 .createSampleRasters();
1030    
1031 alfonx 607 final JPanel panel = new JPanel(new MigLayout("wrap 2, gapy 0"));
1032 alfonx 400
1033 alfonx 516 for (final Double rValue : legendRasterValues) {
1034 alfonx 400
1035 alfonx 516 // final Dimension ICON_SIZE = new Dimension(iconWidth,
1036     // new JLabel().getFontMetrics(new JLabel().getFont())
1037     // .getHeight() > 5 ? new JLabel().getFontMetrics(
1038     // new JLabel().getFont()).getHeight() : iconHeight);
1039 alfonx 400
1040     // ****************************************************************************
1041     // Create the actual icon
1042     // ****************************************************************************
1043 alfonx 516 final BufferedImage buffImage = new BufferedImage(iconWidth,
1044     iconHeight, BufferedImage.TYPE_INT_ARGB);
1045 alfonx 517
1046 alfonx 516 final Graphics2D graphics = buffImage.createGraphics();
1047 alfonx 400
1048 alfonx 405 if (colorModel != null) {
1049 alfonx 516 // The colors come from the ColorModel!
1050 alfonx 517
1051 alfonx 403 try {
1052 alfonx 405 Object inData = null;
1053     switch (colorModel.getTransferType()) {
1054     case DataBuffer.TYPE_BYTE:
1055     inData = new byte[] { rValue.byteValue() };
1056     break;
1057     case DataBuffer.TYPE_USHORT:
1058     inData = new short[] { rValue.shortValue() };
1059     break;
1060     case DataBuffer.TYPE_INT:
1061     inData = new int[] { rValue.intValue() };
1062     break;
1063     case DataBuffer.TYPE_SHORT:
1064     inData = new short[] { rValue.shortValue() };
1065     break;
1066     case DataBuffer.TYPE_FLOAT:
1067     inData = new float[] { rValue.floatValue() };
1068     break;
1069     case DataBuffer.TYPE_DOUBLE:
1070     inData = new double[] { rValue.doubleValue() };
1071     break;
1072     default:
1073     inData = rValue.intValue();
1074     }
1075     final Color color = new Color(colorModel.getRGB(inData));
1076 alfonx 403 graphics.setBackground(color);
1077     graphics.setColor(color);
1078 alfonx 516 graphics.fillRect(0, 0, iconWidth, iconHeight);
1079     } catch (final Exception e) {
1080     LOGGER.info(
1081 alfonx 420 "Dann nehmen wir halt den GridCoverageRenderer", e);
1082 alfonx 405 colorModel = null;
1083     }
1084 alfonx 516 } else {
1085     // The colors come from the Style
1086 alfonx 400
1087 alfonx 405 /**
1088     * The coverage contains only one value of value rValue
1089     */
1090 alfonx 516 final GridCoverage2D sampleCov = sampleRasters.get(rValue);
1091 alfonx 405 GridCoverageRenderer renderer;
1092     try {
1093     renderer = new GridCoverageRenderer(sampleCov
1094     .getCoordinateReferenceSystem(), JTSUtil
1095     .createEnvelope(sampleCov.getEnvelope()),
1096     new Rectangle(iconWidth, iconHeight),
1097     (AffineTransform) null);
1098 alfonx 516 } catch (final Exception e1) {
1099 alfonx 405 throw new RuntimeException(
1100 alfonx 516 "Creating a GridCoverageRenderer failed:", e1);
1101 alfonx 405 }
1102 alfonx 403
1103 alfonx 405 /**
1104     * Iterate over all FeatureTypeStyles.
1105     */
1106 alfonx 516 final List<RasterSymbolizer> rSymbols = StylingUtil
1107 alfonx 405 .getRasterSymbolizers(style);
1108    
1109 alfonx 516 for (final RasterSymbolizer symbolizer : rSymbols) {
1110 alfonx 405 try {
1111     renderer.paint(graphics, sampleCov, symbolizer);
1112 alfonx 516 } catch (final Exception ee) {
1113 alfonx 405 LOGGER.error("Unable to paint " + symbolizer
1114     + " into the legend image", ee);
1115 alfonx 403 }
1116 alfonx 400 }
1117 alfonx 405 }
1118 alfonx 400
1119 alfonx 516 final JLabel iconLabel = new JLabel(new ImageIcon(buffImage));
1120 alfonx 517 panel.add(iconLabel, "sgx1");
1121 alfonx 400
1122 alfonx 516 final Translation labelT = rasterLegendData.get(rValue);
1123 alfonx 400 final JLabel classTitleLabel = new JLabel(labelT.toString());
1124 alfonx 517 panel.add(classTitleLabel, "sgx2"
1125 alfonx 607 + (rasterLegendData.isPaintGaps() ? ", gapy 0:0:0 5:5:5"
1126     : ""));
1127 alfonx 400 classTitleLabel.setLabelFor(iconLabel);
1128    
1129 alfonx 607 if (rasterLegendData.isPaintGaps()) {
1130 alfonx 403 iconLabel
1131     .setBorder(BorderFactory.createLineBorder(Color.black));
1132     }
1133    
1134 alfonx 400 }
1135    
1136 alfonx 516 return panel;
1137 alfonx 397 }
1138 alfonx 824
1139    
1140 alfonx 397
1141 alfonx 405 /**
1142     * Extracts the {@link ColorModel} of any {@link StyledRasterInterface}. May
1143     * return <code>null</code> if the geoobject can not be accessed.
1144     */
1145 alfonx 420 @SuppressWarnings("unchecked")
1146 alfonx 516 public static ColorModel getColorModel(
1147     final StyledRasterInterface<?> styledGrid) {
1148 alfonx 405 ColorModel colorModel = null;
1149     try {
1150 alfonx 516 final Object geoObject = styledGrid.getGeoObject();
1151 alfonx 405 if (geoObject instanceof GridCoverage2D) {
1152 alfonx 516 final GridCoverage2D cov = (GridCoverage2D) geoObject;
1153 alfonx 405 colorModel = cov.getRenderedImage().getColorModel();
1154 alfonx 419 } else if (styledGrid instanceof StyledRasterPyramidInterface) {
1155 alfonx 405
1156 alfonx 516 final Parameter readGG = new Parameter(
1157 alfonx 405 AbstractGridFormat.READ_GRIDGEOMETRY2D);
1158    
1159 alfonx 516 final ReferencedEnvelope mapExtend = new org.geotools.geometry.jts.ReferencedEnvelope(
1160 alfonx 405 styledGrid.getEnvelope(), styledGrid.getCrs());
1161    
1162     readGG.setValue(new GridGeometry2D(new GeneralGridEnvelope(
1163 alfonx 420 new Rectangle(0, 0, 1, 1)), mapExtend));
1164 alfonx 405
1165 alfonx 516 final FeatureCollection<SimpleFeatureType, SimpleFeature> rFc = (FeatureCollection<SimpleFeatureType, SimpleFeature>) geoObject;
1166 alfonx 420
1167     final AbstractGridCoverage2DReader aReader = (AbstractGridCoverage2DReader) FeatureUtil
1168     .getWrappedGeoObject(rFc);
1169 alfonx 516 final GridCoverage2D cov = (GridCoverage2D) aReader
1170 alfonx 405 .read(new GeneralParameterValue[] { readGG });
1171     colorModel = cov.getRenderedImage().getColorModel();
1172     }
1173 alfonx 516 } catch (final Exception e) {
1174 alfonx 420 LOGGER.error("Error reading the colormodel from " + styledGrid, e);
1175 alfonx 405 return null;
1176     }
1177     return colorModel;
1178     }
1179    
1180     /**
1181     * @return <code>true</code> if a {@link RasterSymbolizer} can be applied
1182     * and will have an effect. Some rasters (e.g. GeoTIFF) can come
1183     * with their own {@link ColorModel} and will ignore any
1184     * {@link RasterSymbolizer} = SLD.
1185     */
1186 alfonx 516 public static boolean isStyleable(
1187     final StyledRasterInterface<?> styledRaster) {
1188     final ColorModel colorModel = getColorModel(styledRaster);
1189 alfonx 405
1190 alfonx 607 // LOGGER.info("The colormodel of " + styledRaster.getTitle() + " is "
1191     // + colorModel != null ? colorModel.getClass().getSimpleName() :
1192     // "NULL");
1193    
1194 alfonx 405 if (colorModel == null)
1195     return true;
1196     if (colorModel instanceof ComponentColorModel)
1197     return true;
1198     return false;
1199     }
1200 alfonx 517
1201     /**
1202     * Set the given Style as the Style of the {@link MapLayer}, unless the
1203     * styles are the same (not comparing selection stuff). If the
1204     * {@link MapLayer}s {@link Style} is changed, the selection FTS is kept.<br/>
1205     * Remember {@link MapLayer#setStyle(Style)} triggers an event leading to a
1206     * repaint, so only use it when needed.
1207     *
1208 alfonx 607 * @return <code>true</code> if the {@link MapLayer}'s {@link Style} has
1209     * been changed.
1210 alfonx 517 */
1211 alfonx 607 public static boolean updateMapLayerStyleIfChangedAndKeepSelection(
1212     MapLayer mapLayer, Style style2) {
1213 alfonx 517
1214     Style mapLayerStyleCleaned = StylingUtil
1215 alfonx 607 .removeSelectionFeatureTypeStyle(mapLayer.getStyle());
1216    
1217     Style newStyleCleaned = StylingUtil
1218     .removeSelectionFeatureTypeStyle(style2);
1219    
1220     if (StylingUtil.isStyleDifferent(mapLayerStyleCleaned, newStyleCleaned)) {
1221    
1222 alfonx 517 // They are different when compared without SELECTION FTS!
1223 alfonx 607
1224 alfonx 517 // Now let's copy any SELECTION FTS to the now style
1225 alfonx 607 FeatureTypeStyle selectionFeatureTypeStyle = StylingUtil
1226     .getSelectionFeatureTypeStyle(mapLayer.getStyle());
1227 alfonx 517 if (selectionFeatureTypeStyle != null) {
1228 alfonx 607 newStyleCleaned.featureTypeStyles().add(
1229     selectionFeatureTypeStyle);
1230     // newStyleCleaned is not so clean anymore... We just alled a
1231     // selcetion FTS
1232     }
1233    
1234 alfonx 517 mapLayer.setStyle(newStyleCleaned);
1235 alfonx 607
1236 alfonx 517 return true;
1237 alfonx 607
1238 alfonx 526 } else {
1239     return false;
1240     }
1241 alfonx 517 }
1242    
1243 alfonx 607 /**
1244     * After loading an atlas, the AttribteMetaData contains whatever is written
1245     * in the XML. But the DBF may have changed! This method checks an
1246     * {@link AttributeMetadataMap} against a schema and also corrects
1247     * upperCase/lowerCase problems. It will also remove any geometry column
1248     * attribute metadata.
1249     */
1250     /**
1251     * After loading an atlas, the AttribteMetaData contains whatever is written
1252     * in the XML. But the DBF may have changed!
1253     */
1254 alfonx 677 public static void checkAttribMetaData(
1255 alfonx 769 AttributeMetadataMap<AttributeMetadataImpl> attributeMetaDataMap,
1256     SimpleFeatureType schema) {
1257 alfonx 607
1258 alfonx 769 if (schema == null)
1259     throw new IllegalArgumentException("schmema may not be null!");
1260    
1261 alfonx 607 ArrayList<Name> willRemove = new ArrayList<Name>();
1262    
1263     // 1. Check.. all attributes in the atm should be in the schema as well.
1264     // maybe correct some upperCase/loweCase stuff
1265    
1266 alfonx 772 for (AttributeMetadataInterface atm : attributeMetaDataMap.values()) {
1267 alfonx 607
1268     AttributeDescriptor foundDescr = schema
1269     .getDescriptor(atm.getName());
1270     if (foundDescr == null) {
1271 alfonx 770 NameImpl bestMatch = FeatureUtil.findBestMatchingAttribute(schema,
1272 alfonx 607 atm.getLocalName());
1273     if (bestMatch == null)
1274     willRemove.add(atm.getName());
1275     else
1276     atm.setName(bestMatch);
1277     } else if (foundDescr instanceof GeometryDescriptor) {
1278     // We don't want GeometryColumns in here
1279     willRemove.add(atm.getName());
1280     }
1281     }
1282    
1283     // Remove the ones that were not findable in the schema
1284     for (Name removeName : willRemove) {
1285 alfonx 677 if (attributeMetaDataMap.remove(removeName) == null) {
1286 alfonx 607 LOGGER.warn("removing the AMData didn't work");
1287     }
1288     }
1289    
1290     // 2. check... all attributes from the schema must have an ATM
1291     for (AttributeDescriptor ad : schema.getAttributeDescriptors()) {
1292     if (ad instanceof GeometryDescriptor)
1293     continue;
1294     if (!attributeMetaDataMap.containsKey(ad.getName())) {
1295 alfonx 770 attributeMetaDataMap.put( new NameImpl(ad.getName().getNamespaceURI(), ad.getName().getLocalPart()),
1296 alfonx 769 new AttributeMetadataImpl(ad, schema
1297     .getAttributeDescriptors().indexOf(ad),
1298     attributeMetaDataMap.getLanguages()));
1299 alfonx 607 }
1300     }
1301     }
1302    
1303 alfonx 677 /**
1304     * Checks every attribute name in the {@link AttributeMetadataMap} for its
1305     * binding type. It the type is textual, add the mrpty string as a NODATA
1306     * value.
1307     *
1308     * @param attributeMetaDataMap
1309     * @param schema
1310     */
1311     public static void addEmptyStringToAllTextualAttributes(
1312 alfonx 772 AttributeMetadataMap<? extends AttributeMetadataInterface> attributeMetaDataMap,
1313 alfonx 769 SimpleFeatureType schema) {
1314 alfonx 677
1315     for (Name name : attributeMetaDataMap.keySet()) {
1316     if (String.class.isAssignableFrom(schema.getDescriptor(name)
1317     .getType().getBinding())) {
1318     attributeMetaDataMap.get(name).getNodataValues().add("");
1319     }
1320     }
1321     }
1322 alfonx 769
1323     /**
1324     * @return a nicely formatted String containing all NODATA values of any
1325 alfonx 772 * {@link AttributeMetadataInterface} object. Strings are quoted so that any
1326 alfonx 769 * empty {@link String} can be seen.
1327     */
1328     public static String formatNoDataValues(Set<Object> nodataValuesList) {
1329     String nicelyFormatted = "";
1330     if (nodataValuesList != null) {
1331     if (nodataValuesList.size() == 0)
1332     nicelyFormatted = "";
1333     else {
1334     for (Object ndo : nodataValuesList) {
1335     if (ndo instanceof String)
1336     nicelyFormatted += "\"" + ndo + "\"";
1337     else
1338     nicelyFormatted += ndo.toString();
1339    
1340     nicelyFormatted += ",";
1341     }
1342     // Remove the extra comma
1343     nicelyFormatted = nicelyFormatted.substring(0, nicelyFormatted
1344     .length() - 1);
1345     }
1346     }
1347     return nicelyFormatted;
1348     }
1349 alfonx 244 }

[email protected]
ViewVC Help
Powered by ViewVC 1.1.26