changeset 6908:819481cc9195

Artifacts: ThemeDocument. The bloody part: Removal of the XPaths. Now the theme XML document is scanned once(!) at construction time for field values and the resulting key/value pairs are store in a map.
author Sascha L. Teichmann <teichmann@intevation.de>
date Fri, 23 Aug 2013 11:07:11 +0200
parents dbad1f442f3e
children 835e07ee769d
files artifacts/src/main/java/org/dive4elements/river/exports/ChartGenerator.java artifacts/src/main/java/org/dive4elements/river/jfree/StyledAreaSeriesCollection.java artifacts/src/main/java/org/dive4elements/river/jfree/StyledDomainMarker.java artifacts/src/main/java/org/dive4elements/river/themes/ThemeDocument.java
diffstat 4 files changed, 165 insertions(+), 201 deletions(-) [+]
line wrap: on
line diff
--- a/artifacts/src/main/java/org/dive4elements/river/exports/ChartGenerator.java	Fri Aug 23 01:17:13 2013 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/exports/ChartGenerator.java	Fri Aug 23 11:07:11 2013 +0200
@@ -1835,7 +1835,11 @@
     public LegendItem createLegendItem(ThemeDocument theme, String name) {
         // OPTIMIZE Pass font, parsed Theme items.
 
-        Color      color       = theme.parseComplexLineColorField();
+        Color color = theme.parseLineColorField();
+        if (color == null) {
+            color = Color.BLACK;
+        }
+
         LegendItem legendItem  = new LegendItem(name, color);
 
         legendItem.setLabelFont(createLegendLabelFont());
--- a/artifacts/src/main/java/org/dive4elements/river/jfree/StyledAreaSeriesCollection.java	Fri Aug 23 01:17:13 2013 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/jfree/StyledAreaSeriesCollection.java	Fri Aug 23 11:07:11 2013 +0200
@@ -88,8 +88,7 @@
 
 
     protected void applyFillColor(StableXYDifferenceRenderer renderer) {
-        Color paint = ThemeDocument.parseColor(
-                theme.getAreaBackgroundColorString());
+        Color paint = theme.parseAreaBackgroundColor();
 
         int transparency = theme.parseAreaTransparency();
         if (transparency > 0 && paint != null) {
--- a/artifacts/src/main/java/org/dive4elements/river/jfree/StyledDomainMarker.java	Fri Aug 23 01:17:13 2013 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/jfree/StyledDomainMarker.java	Fri Aug 23 11:07:11 2013 +0200
@@ -28,16 +28,14 @@
     public StyledDomainMarker(double start, double end, ThemeDocument theme) {
         super(start, end);
 
-        backgroundColor = ThemeDocument.parseColor(
-                theme.getAreaBackgroundColorString());
+        backgroundColor = theme.parseAreaBackgroundColor();
         backgroundColor2 = new Color(
             255 - backgroundColor.getRed(),
             255 - backgroundColor.getGreen(),
             255 - backgroundColor.getBlue());
         useSecondColor(false);
 
-        int alpha = 100 - ThemeDocument.parseInteger(
-                theme.getAreaTransparencyString(), 50);
+        int alpha = 100 - theme.parseAreaTransparency(50);
         setAlpha(alpha / 100.0f);
     }
 
--- a/artifacts/src/main/java/org/dive4elements/river/themes/ThemeDocument.java	Fri Aug 23 01:17:13 2013 +0200
+++ b/artifacts/src/main/java/org/dive4elements/river/themes/ThemeDocument.java	Fri Aug 23 11:07:11 2013 +0200
@@ -10,10 +10,11 @@
 
 import java.awt.Color;
 import java.awt.Font;
+import java.util.HashMap;
+import java.util.Map;
 
 import org.apache.log4j.Logger;
 import org.dive4elements.artifacts.CallMeta;
-import org.dive4elements.artifacts.common.utils.XMLUtils;
 import org.dive4elements.river.artifacts.model.MapserverStyle;
 import org.dive4elements.river.artifacts.model.MapserverStyle.Clazz;
 import org.dive4elements.river.artifacts.model.MapserverStyle.Expression;
@@ -21,6 +22,8 @@
 import org.dive4elements.river.artifacts.model.MapserverStyle.Style;
 import org.dive4elements.river.artifacts.resources.Resources;
 import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+import org.w3c.dom.NodeList;
 
 public class ThemeDocument
 {
@@ -30,152 +33,131 @@
 
     private static final String MSG_ISOBATH_LASTCLASS = "floodmap.isobath.lastclass";
 
-    public final static String XPATH_FILL_COLOR =
-            "/theme/field[@name='fillcolor']/@default";
-
-    public final static String XPATH_LINE_COLOR =
-            "/theme/field[@name='linecolor']/@default";
-
-    public final static String XPATH_AREA_LINE_COLOR =
-            "/theme/field[@name='areabordercolor']/@default";
-
-    public static final String XPATH_LINE_SIZE =
-            "/theme/field[@name='linesize']/@default";
-
-    public static final String XPATH_LINE_STYLE =
-            "/theme/field[@name='linetype']/@default";
-
-    public static final String XPATH_POINT_SIZE =
-            "/theme/field[@name='pointsize']/@default";
-
-    public static final String XPATH_POINT_COLOR =
-            "/theme/field[@name='pointcolor']/@default";
-
-    public final static String XPATH_SHOW_BORDER =
-            "/theme/field[@name='showborder']/@default";
-
-    public final static String XPATH_AREA_SHOW_BORDER =
-            "/theme/field[@name='showborder']/@default";
-
-    public final static String XPATH_SHOW_POINTS =
-            "/theme/field[@name='showpoints']/@default";
-
-    public final static String XPATH_SHOW_LINE =
-            "/theme/field[@name='showlines']/@default";
-
-    public final static String XPATH_SHOW_VERTICAL_LINE =
-            "/theme/field[@name='showverticalline']/@default";
-
-    public final static String XPATH_SHOW_HORIZONTAL_LINE =
-            "/theme/field[@name='showhorizontalline']/@default";
-
-    public final static String XPATH_SHOW_LINE_LABEL =
-            "/theme/field[@name='showlinelabel']/@default";
-
-    public final static String XPATH_SHOW_POINT_LABEL =
-            "/theme/field[@name='showpointlabel']/@default";
-
-    public final static String XPATH_SHOW_WIDTH =
-            "/theme/field[@name='showwidth']/@default";
-
-    public final static String XPATH_SHOW_LEVEL =
-            "/theme/field[@name='showlevel']/@default";
-
-    public final static String XPATH_TRANSPARENCY =
-            "/theme/field[@name='transparency']/@default";
-
-    public final static String XPATH_AREA_TRANSPARENCY =
-            "/theme/field[@name='areatransparency']/@default";
+    public final static String FILL_COLOR = "fillcolor";
 
-    public final static String XPATH_SHOW_AREA =
-            "/theme/field[@name='showarea']/@default";
-
-    public final static String XPATH_SHOW_MIDDLE_HEIGHT =
-            "/theme/field[@name='showmiddleheight']/@default";
-
-    public final static String XPATH_LABEL_FONT_COLOR =
-            "/theme/field[@name='labelfontcolor']/@default";
-
-    public final static String XPATH_LABEL_FONT_SIZE =
-            "/theme/field[@name='labelfontsize']/@default";
-
-    public final static String XPATH_LABEL_FONT_FACE =
-            "/theme/field[@name='labelfontface']/@default";
-
-    public final static String XPATH_LABEL_FONT_STYLE =
-            "/theme/field[@name='labelfontstyle']/@default";
-
-    public final static String XPATH_TEXT_ORIENTATION =
-            "/theme/field[@name='textorientation']/@default";
-
-    public final static String XPATH_LABEL_BGCOLOR =
-            "/theme/field[@name='labelbgcolor']/@default";
-
-    public final static String XPATH_LABEL_SHOW_BACKGROUND =
-            "/theme/field[@name='labelshowbg']/@default";
-
-    public final static String XPATH_BACKGROUND_COLOR =
-            "/theme/field[@name='backgroundcolor']/@default";
+    public final static String LINE_COLOR = "linecolor";
 
-    public final static String XPATH_AREA_BACKGROUND_COLOR =
-            "/theme/field[@name='areabgcolor']/@default";
-
-    public final static String XPATH_SYMBOL =
-            "/theme/field[@name='symbol']/@default";
-
-    public final static String XPATH_SHOW_MINIMUM =
-            "/theme/field[@name='showminimum']/@default";
-
-    public final static String XPATH_SHOW_MAXIMUM =
-            "/theme/field[@name='showmaximum']/@default";
-
-    public final static String XPATH_WSPLGEN_FIELDS =
-            "/theme[@name='WSPLGEN']/field";
+    public final static String AREA_LINE_COLOR = "areabordercolor";
 
-    public final static String XPATH_WSPLGEN_STARTCOLOR =
-            "/theme/field[@name='startcolor']/@default";
-
-    public final static String XPATH_WSPLGEN_ENDCOLOR =
-            "/theme/field[@name='endcolor']/@default";
+    public static final String LINE_SIZE = "linesize";
 
-    public final static String XPATH_WSPLGEN_NUMCLASSES =
-            "/theme/field[@name='numclasses']/@default";
+    public static final String LINE_STYLE = "linetype";
 
-    /** XPATH to bandwidth field. */
-    public final static String XPATH_BANDWIDTH =
-            "/theme/field[@name='bandwidth']/@default";
+    public static final String POINT_SIZE = "pointsize";
 
-    /** XPATH to find showextramark field. */
-    public final static String XPATH_SHOWEXTRAMARK =
-            "/theme/field[@name='showextramark']/@default";
+    public static final String POINT_COLOR = "pointcolor";
+
+    public final static String SHOW_BORDER = "showborder";
+
+    public final static String AREA_SHOW_BORDER = "showborder";
+
+    public final static String SHOW_POINTS = "showpoints";
+
+    public final static String SHOW_LINE = "showlines";
+
+    public final static String SHOW_VERTICAL_LINE = "showverticalline";
+
+    public final static String SHOW_HORIZONTAL_LINE = "showhorizontalline";
+
+    public final static String SHOW_LINE_LABEL = "showlinelabel";
+
+    public final static String SHOW_POINT_LABEL = "showpointlabel";
+
+    public final static String SHOW_WIDTH = "showwidth";
+
+    public final static String SHOW_LEVEL = "showlevel";
+
+    public final static String TRANSPARENCY = "transparency";
+
+    public final static String AREA_TRANSPARENCY = "areatransparency";
+
+    public final static String SHOW_AREA = "showarea";
+
+    public final static String SHOW_MIDDLE_HEIGHT = "showmiddleheight";
+
+    public final static String LABEL_FONT_COLOR = "labelfontcolor";
+
+    public final static String LABEL_FONT_SIZE = "labelfontsize";
+
+    public final static String LABEL_FONT_FACE = "labelfontface";
+
+    public final static String LABEL_FONT_STYLE = "labelfontstyle";
+
+    public final static String TEXT_ORIENTATION = "textorientation";
+
+    public final static String LABEL_BGCOLOR = "labelbgcolor";
+
+    public final static String LABEL_SHOW_BACKGROUND = "labelshowbg";
+
+    public final static String BACKGROUND_COLOR = "backgroundcolor";
+
+    public final static String AREA_BACKGROUND_COLOR = "areabgcolor";
+
+    public final static String SYMBOL = "symbol";
+
+    public final static String SHOW_MINIMUM = "showminimum";
+
+    public final static String SHOW_MAXIMUM = "showmaximum";
+
+    public final static String WSPLGEN_FIELDS = "/theme[@name='WSPLGEN']/field";
+
+    public final static String WSPLGEN_STARTCOLOR = "startcolor";
+
+    public final static String WSPLGEN_ENDCOLOR = "endcolor";
+
+    public final static String WSPLGEN_NUMCLASSES = "numclasses";
+
+    public final static String BANDWIDTH = "bandwidth";
+
+    public final static String SHOWEXTRAMARK = "showextramark";
+
 
     private Document document;
 
+    private Map<String, String> values;
+
     public ThemeDocument() {
     }
 
     public ThemeDocument(Document document) {
         this.document = document;
+        values = extractValues(document);
     }
 
     public Document getDocument() {
         return document;
     }
 
+    private String getValue(String key) {
+        return values.get(key);
+    }
+
+    private static Map<String, String> extractValues(Document document) {
+        Map<String, String> values = new HashMap<String, String>();
+        NodeList fields = document.getElementsByTagName("field");
+        for (int i = 0, N = fields.getLength(); i < N; ++i) {
+            Element field = (Element)fields.item(i);
+            String name   = field.getAttribute("name");
+            String value  = field.getAttribute("default");
+            if (!name.isEmpty() && !value.isEmpty()) {
+                values.put(name, value);
+            }
+        }
+        return values;
+    }
+
     /** Parse string to be boolean with default if empty or unrecognized. */
-    public static boolean parseBoolean(String value, boolean defaultsTo) {
+    private static boolean parseBoolean(String value, boolean defaultsTo) {
         if (value == null || value.length() == 0) {
             return defaultsTo;
         }
         if (value.equals("false")) {
             return false;
         }
-        else if (value.equals("true")) {
+        if (value.equals("true")) {
             return true;
         }
-        else {
-            return defaultsTo;
-        }
+        return defaultsTo;
     }
 
 
@@ -186,7 +168,7 @@
      * @param defaultsTo Default to return if conversion failed.
      * @return \param value as integer or defaultsto if conversion failed.
      */
-    public static int parseInteger(String value, int defaultsTo) {
+    private static int parseInteger(String value, int defaultsTo) {
         if (value == null || value.length() == 0) {
             return defaultsTo;
         }
@@ -209,7 +191,7 @@
      * @param defaultsTo Default to return if conversion failed.
      * @return \param value as integer or defaultsto if conversion failed.
      */
-    public static double parseDouble(String value, double defaultsTo) {
+    private static double parseDouble(String value, double defaultsTo) {
         if (value == null || value.length() == 0) {
             return defaultsTo;
         }
@@ -225,42 +207,40 @@
     }
 
     public boolean parseShowLineLabel() {
-        String show = XMLUtils.xpathString(document, XPATH_SHOW_LINE_LABEL, null);
+        String show = getValue(SHOW_LINE_LABEL);
         return parseBoolean(show, false);
     }
 
     public boolean parseShowWidth() {
-        String show = XMLUtils.xpathString(document, XPATH_SHOW_WIDTH, null);
+        String show = getValue(SHOW_WIDTH);
         return parseBoolean(show, false);
     }
 
     public boolean parseShowLevel() {
-        String show = XMLUtils.xpathString(document, XPATH_SHOW_LEVEL, null);
+        String show = getValue(SHOW_LEVEL);
         return parseBoolean(show, false);
     }
 
     public String parseTextOrientation() {
-        String o = XMLUtils.xpathString(document, XPATH_TEXT_ORIENTATION, null);
-        if ("true".equals(o)) {
-            return "horizontal";
-        }
-        else {
-            return "vertical";
-        }
+        String o = getValue(TEXT_ORIENTATION);
+
+        return o != null && "true".equals(o)
+            ? "horizontal"
+            : "vertical";
     }
 
     public boolean parseShowMiddleHeight() {
-        String show = XMLUtils.xpathString(document, XPATH_SHOW_MIDDLE_HEIGHT, null);
+        String show = getValue(SHOW_MIDDLE_HEIGHT);
         return parseBoolean(show, false);
     }
 
     public boolean parseLabelShowBackground() {
-        String show = XMLUtils.xpathString(document, XPATH_LABEL_SHOW_BACKGROUND, null);
+        String show = getValue(LABEL_SHOW_BACKGROUND);
         return parseBoolean(show, false);
     }
 
     public Font parseTextFont() {
-        String font = XMLUtils.xpathString(document, XPATH_LABEL_FONT_FACE, null);
+        String font = getValue(LABEL_FONT_FACE);
         if (font == null || font.length() == 0) {
             return null;
         }
@@ -276,7 +256,7 @@
     }
 
     public String getTextColorString() {
-        String textColor = XMLUtils.xpathString(document, XPATH_LABEL_FONT_COLOR, null);
+        String textColor = getValue(LABEL_FONT_COLOR);
         return textColor;
     }
 
@@ -288,13 +268,13 @@
         return parseRGB(color);
     }
 
-    public String getLabelBackgroundColorString() {
-        return XMLUtils.xpathString(document, XPATH_LABEL_BGCOLOR, null);
+    private String getLabelBackgroundColorString() {
+        return getValue(LABEL_BGCOLOR);
     }
 
 
     public int parseLineWidth() {
-        String size = XMLUtils.xpathString(document, XPATH_LINE_SIZE, null);
+        String size = getValue(LINE_SIZE);
         if (size == null || size.length() == 0) {
             return 0;
         }
@@ -309,7 +289,7 @@
     }
 
     public float [] parseLineStyle() {
-        String dash = XMLUtils.xpathString(document, XPATH_LINE_STYLE, null);
+        String dash = getValue(LINE_STYLE);
 
         float[] def = {10};
         if (dash == null || dash.length() == 0) {
@@ -328,40 +308,34 @@
             }
             return dashes;
         }
-        catch(NumberFormatException nfe) {
+        catch (NumberFormatException nfe) {
             logger.warn("Unable to set dash from string: '" + dash + "'");
             return def;
         }
     }
 
     public int parsePointWidth() {
-        String width = XMLUtils.xpathString(document, XPATH_POINT_SIZE, null);
-
+        String width = getValue(POINT_SIZE);
         return parseInteger(width, 3);
     }
 
     public Color parsePointColor() {
-        String color = XMLUtils.xpathString(document, XPATH_POINT_COLOR, null);
-        logger.debug("parsePointColor(): color = " + color);
+        String color = getValue(POINT_COLOR);
         return parseColor(color);
     }
 
     public boolean parseShowPoints() {
-        String show = XMLUtils.xpathString(document, XPATH_SHOW_POINTS, null);
+        String show = getValue(SHOW_POINTS);
         return parseBoolean(show, false);
     }
 
     public boolean parseShowLine() {
-        String show = XMLUtils.xpathString(document, XPATH_SHOW_LINE, null);
+        String show = getValue(SHOW_LINE);
         return parseBoolean(show, true);
     }
 
     public int parseTextStyle() {
-        return parseTextStyle(XPATH_LABEL_FONT_STYLE);
-    }
-
-    public int parseTextStyle(String path) {
-        String style = XMLUtils.xpathString(document, path, null);
+        String style = getValue(LABEL_FONT_STYLE);
         if (style == null || style.length() == 0) {
             return Font.PLAIN;
         }
@@ -369,12 +343,10 @@
         if (style.equals("italic")) {
             return Font.ITALIC;
         }
-        else if (style.equals("bold")) {
+        if (style.equals("bold")) {
             return Font.BOLD;
         }
-        else {
-            return Font.PLAIN;
-        }
+        return Font.PLAIN;
     }
 
     public TextStyle parseComplexTextStyle() {
@@ -392,22 +364,18 @@
             Integer.valueOf(parseLineWidth()));
     }
 
-    public Color parseComplexLineColorField() {
-        return null;
-    }
-
     public boolean parseShowVerticalLine() {
-        String show = XMLUtils.xpathString(document, XPATH_SHOW_VERTICAL_LINE, null);
+        String show = getValue(SHOW_VERTICAL_LINE);
         return parseBoolean(show, true);
     }
 
     public boolean parseShowHorizontalLine() {
-        String show = XMLUtils.xpathString(document, XPATH_SHOW_HORIZONTAL_LINE, null);
+        String show = getValue(SHOW_HORIZONTAL_LINE);
         return parseBoolean(show, true);
     }
 
     public double parseBandWidth() {
-        String bandWidth = XMLUtils.xpathString(document, XPATH_BANDWIDTH, null);
+        String bandWidth = getValue(BANDWIDTH);
         return parseDouble(bandWidth, 0);
     }
 
@@ -443,26 +411,22 @@
 
 
     public boolean parseShowArea() {
-        String show = XMLUtils.xpathString(document, XPATH_SHOW_AREA, null);
+        String show = getValue(SHOW_AREA);
         return parseBoolean(show, false);
     }
 
     public boolean parseShowPointLabel() {
-        String show = XMLUtils.xpathString(document, XPATH_SHOW_POINT_LABEL, null);
+        String show = getValue(SHOW_POINT_LABEL);
         return parseBoolean(show, false);
     }
 
     public boolean parseShowExtraMark() {
-        String show = XMLUtils.xpathString(document, XPATH_SHOWEXTRAMARK, null);
+        String show = getValue(SHOWEXTRAMARK);
         return parseBoolean(show, false);
     }
 
     public int parseTextSize() {
-        return parseTextSize(XPATH_LABEL_FONT_SIZE);
-    }
-
-    public int parseTextSize(String path) {
-        String size = XMLUtils.xpathString(document, path, null);
+        String size = getValue(LABEL_FONT_SIZE);
         if (size == null || size.length() == 0) {
             return 10;
         }
@@ -499,48 +463,43 @@
     }
 
     public String getLineColorString() {
-        return XMLUtils.xpathString(document, XPATH_LINE_COLOR, null);
+        return getValue(LINE_COLOR);
     }
 
 
     /** Get show border as string. */
     public String getShowBorderString() {
-        return XMLUtils.xpathString(document, XPATH_SHOW_BORDER, null);
+        return getValue(SHOW_BORDER);
     }
 
 
     /** Get fill color as string. */
-    public String getFillColorString() {
-        return XMLUtils.xpathString(document, XPATH_FILL_COLOR, null);
+    private String getFillColorString() {
+        return getValue(FILL_COLOR);
+    }
+
+    public String getSymbol() {
+        return getValue(SYMBOL);
     }
 
 
-    public String getBackgroundColorString() {
-        return XMLUtils.xpathString(document, XPATH_BACKGROUND_COLOR, null);
-    }
-
-    public String getSymbol() {
-        return XMLUtils.xpathString(document, XPATH_SYMBOL, null);
-    }
-
-
-    public String getTransparencyString() {
-        return XMLUtils.xpathString(document, XPATH_TRANSPARENCY, null);
+    private String getTransparencyString() {
+        return getValue(TRANSPARENCY);
     }
 
 
     public String getAreaTransparencyString() {
-        return XMLUtils.xpathString(document, XPATH_AREA_TRANSPARENCY, null);
+        return getValue(AREA_TRANSPARENCY);
     }
 
 
     public String getShowMinimum() {
-        return XMLUtils.xpathString(document, XPATH_SHOW_MINIMUM, null);
+        return getValue(SHOW_MINIMUM);
     }
 
 
     public String getShowMaximum() {
-        return XMLUtils.xpathString(document, XPATH_SHOW_MAXIMUM, null);
+        return getValue(SHOW_MAXIMUM);
     }
 
 
@@ -586,7 +545,7 @@
 
 
     private String getAreaLineColorString() {
-        return XMLUtils.xpathString(document, XPATH_AREA_LINE_COLOR, null);
+        return getValue(AREA_LINE_COLOR);
     }
 
 
@@ -612,9 +571,9 @@
     {
         MapserverStyle ms = new MapserverStyle();
 
-        String strStartColor = XMLUtils.xpathString(document, XPATH_WSPLGEN_STARTCOLOR, null);
+        String strStartColor = getValue(WSPLGEN_STARTCOLOR);
         Color startColor = strStartColor != null ? parseColor(strStartColor) : new Color(178, 201, 215);
-        String strEndColor = XMLUtils.xpathString(document, XPATH_WSPLGEN_ENDCOLOR, null);
+        String strEndColor = getValue(WSPLGEN_ENDCOLOR);
         Color endColor = strEndColor != null? parseColor(strEndColor) : new Color(2, 27, 42);
 
         to = to != 0 ? to : 9999;
@@ -733,8 +692,8 @@
     }
 
 
-    public String getAreaBackgroundColorString() {
-        return XMLUtils.xpathString(document, XPATH_AREA_BACKGROUND_COLOR, null);
+    private String getAreaBackgroundColorString() {
+        return getValue(AREA_BACKGROUND_COLOR);
     }
 
 
@@ -744,7 +703,11 @@
 
 
     public int parseAreaTransparency() {
-        return parseInteger(getAreaTransparencyString(), 50);
+        return parseAreaTransparency(50);
+    }
+
+    public int parseAreaTransparency(int alpha) {
+        return parseInteger(getAreaTransparencyString(), alpha);
     }
 
 
@@ -754,7 +717,7 @@
 
 
     private String getAreaShowBorderString() {
-        return XMLUtils.xpathString(document, XPATH_AREA_SHOW_BORDER, null);
+        return getValue(AREA_SHOW_BORDER);
     }
 }
 // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :

http://dive4elements.wald.intevation.org