Index: /trunk/src/org/openstreetmap/josm/data/osm/Way.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/Way.java	(revision 1189)
+++ /trunk/src/org/openstreetmap/josm/data/osm/Way.java	(revision 1190)
@@ -117,3 +117,8 @@
         return name;
     }
+
+    public Boolean isClosed() {
+        int s = nodes.size();
+        return s >= 3 && nodes.get(0) == nodes.get(s-1);
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/data/osm/visitor/MapPaintVisitor.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/visitor/MapPaintVisitor.java	(revision 1189)
+++ /trunk/src/org/openstreetmap/josm/data/osm/visitor/MapPaintVisitor.java	(revision 1190)
@@ -12,4 +12,5 @@
 import java.awt.Stroke;
 import java.awt.geom.GeneralPath;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.LinkedList;
@@ -23,4 +24,5 @@
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.RelationMember;
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.data.osm.visitor.SimplePaintVisitor;
@@ -46,4 +48,6 @@
     protected double circum;
     protected String regionalNameOrder[];
+    protected Collection<Way> alreadyDrawnWays = new LinkedList<Way>();
+    protected Collection<Way> alreadyDrawnAreas = new LinkedList<Way>();
 
     protected boolean isZoomOk(ElemStyle e) {
@@ -87,13 +91,5 @@
         if(w.nodes.size() < 2)
             return;
-        // show direction arrows, if draw.segment.relevant_directions_only is not set, the way is tagged with a direction key
-        // (even if the tag is negated as in oneway=false) or the way is selected
-        boolean showDirection = w.selected || ((!useRealWidth) && (showDirectionArrow
-         && (!showRelevantDirectionsOnly || w.hasDirectionKeys)));
-
-        Color color = untaggedColor;
-        int width = defaultSegmentWidth;
-        int realWidth = 0; //the real width of the element in meters
-        boolean dashed = false;
+
         ElemStyle wayStyle = styles.get(w);
 
@@ -102,7 +98,7 @@
 
         LineElemStyle l = null;
+        Color areacolor = untaggedColor;
         if(wayStyle!=null)
         {
-            Color areacolor = untaggedColor;
             boolean area = false;
             if(wayStyle instanceof LineElemStyle)
@@ -111,19 +107,31 @@
             {
                 areacolor = ((AreaElemStyle)wayStyle).color;
-                color = areacolor;
                 l = ((AreaElemStyle)wayStyle).line;
                 area = true;
             }
-            if(l != null)
-            {
-                color = l.color;
-                width = l.width;
-                realWidth = l.realWidth;
-                dashed = l.dashed;
-            }
             if (area && fillAreas)
                 drawWayAsArea(w, areacolor);
         }
 
+        drawWay(w, l, areacolor);
+    }
+
+    public void drawWay(Way w, LineElemStyle l, Color color) {
+        // show direction arrows, if draw.segment.relevant_directions_only is not set,
+        // the way is tagged with a direction key
+        // (even if the tag is negated as in oneway=false) or the way is selected
+        boolean showDirection = w.selected || ((!useRealWidth) && (showDirectionArrow
+        && (!showRelevantDirectionsOnly || w.hasDirectionKeys)));
+        int width = defaultSegmentWidth;
+        int realWidth = 0; //the real width of the element in meters
+        boolean dashed = false;
+
+        if(l != null)
+        {
+            color = l.color;
+            width = l.width;
+            realWidth = l.realWidth;
+            dashed = l.dashed;
+        }
         if (realWidth > 0 && useRealWidth && !showDirection)
         {
@@ -200,9 +208,249 @@
     }
 
-    public void visit(Relation e) {
-        // relations are not (yet?) drawn.
-    }
-
-    // This assumes that all segments are aligned in the same direction!
+    public Collection<Way> joinWays(Collection<Way> join)
+    {
+        Collection<Way> res = new LinkedList<Way>();
+        Object[] joinArray = join.toArray();
+        int left = join.size();
+        while(left != 0)
+        {
+            Way w = null;
+            Boolean selected = false;
+            ArrayList<Node> n = null;
+            Boolean joined = true;
+            while(joined && left != 0)
+            {
+                joined = false;
+                for(int i = 0; i < joinArray.length && left != 0; ++i)
+                {
+                    if(joinArray[i] != null)
+                    {
+                        Way c = (Way)joinArray[i];
+                        if(w == null)
+                        { w = c; selected = w.selected; joinArray[i] = null; --left; }
+                        else
+                        {
+                            int mode = 0;
+                            int cl = c.nodes.size()-1;
+                            int nl;
+                            if(n == null)
+                            {
+                                nl = w.nodes.size()-1;
+                                if(w.nodes.get(nl) == c.nodes.get(0)) mode = 21;
+                                else if(w.nodes.get(nl) == c.nodes.get(cl)) mode = 22;
+                                else if(w.nodes.get(0) == c.nodes.get(0)) mode = 11;
+                                else if(w.nodes.get(0) == c.nodes.get(cl)) mode = 12;
+                            }
+                            else
+                            {
+                                nl = n.size()-1;
+                                if(n.get(nl) == c.nodes.get(0)) mode = 21;
+                                else if(n.get(0) == c.nodes.get(cl)) mode = 12;
+                                else if(n.get(0) == c.nodes.get(0)) mode = 11;
+                                else if(n.get(nl) == c.nodes.get(cl)) mode = 22;
+                            }
+                            if(mode != 0)
+                            {
+                                joinArray[i] = null;
+                                joined = true;
+                                if(c.selected) selected = true;
+                                --left;
+                                if(n == null) n = new ArrayList(w.nodes);
+System.out.println("old: " + n);
+System.out.println("new: " + c.nodes);
+                                n.remove((mode == 21 || mode == 22) ? nl : 0);
+                                if(mode == 21)
+                                    n.addAll(c.nodes);
+                                else if(mode == 12)
+                                    n.addAll(0, c.nodes);
+                                else if(mode == 22)
+                                {
+                                    for(Node node : c.nodes)
+                                        n.add(nl, node);
+System.out.println("ERROR: Joining way reversed: " + c);
+                                }
+                                else /* mode == 11 */
+                                {
+                                    for(Node node : c.nodes)
+                                        n.add(0, node);
+System.out.println("ERROR: Joining way reversed: " + c);
+                                }
+System.out.println("joined: " + n);
+                            }
+                        }
+                    }
+                } /* for(i = ... */
+            } /* while(joined) */
+            if(n != null)
+            {
+                w = new Way(w);
+                w.nodes.clear();
+                w.nodes.addAll(n);
+                w.selected = selected;
+            }
+            if(!w.isClosed())
+            {
+System.out.println("ERROR: multipolygon way is not closed." + w);
+            }
+            res.add(w);
+        } /* while(left != 0) */
+
+        return res;
+    }
+
+    public void visit(Relation r) {
+        // draw multipolygon relations including their ways
+        // other relations are not (yet?) drawn.
+        if (r.incomplete) return;
+
+        if(!Main.pref.getBoolean("mappaint.multipolygon",false)) return;
+
+        if(!"multipolygon".equals(r.keys.get("type"))) return;
+
+        Collection<Way> inner = new LinkedList<Way>();
+        Collection<Way> outer = new LinkedList<Way>();
+        Collection<Way> innerclosed = new LinkedList<Way>();
+        Collection<Way> outerclosed = new LinkedList<Way>();
+
+        for (RelationMember m : r.members)
+        {
+            if (!m.member.incomplete && !m.member.deleted)
+            {
+                if(m.member instanceof Way)
+                {
+                    Way w = (Way) m.member;
+                    if(w.nodes.size() < 2)
+                    {
+System.out.println("ERROR: Way with less than two points " + w);
+                    }
+                    else if("inner".equals(m.role))
+                        inner.add(w);
+                    else if("outer".equals(m.role))
+                        outer.add(w);
+                    else
+                    {
+System.out.println("ERROR: No useful role for Way " + w);
+                        if(m.role == null || m.role.length() == 0)
+                            outer.add(w);
+                    }
+                }
+                else
+                {
+System.out.println("ERROR: Non-Way in multipolygon " + m.member);
+                }
+            }
+        }
+
+        ElemStyle wayStyle = styles.get(r);
+        /* find one wayStyle, prefer the style from Relation or take the first
+        one of outer rings */
+        if(wayStyle == null || !(wayStyle instanceof AreaElemStyle))
+        {
+            for (Way w : outer)
+            {
+               if(wayStyle == null || !(wayStyle instanceof AreaElemStyle))
+                   wayStyle = styles.get(w);
+            }
+        }
+
+        if(wayStyle != null && wayStyle instanceof AreaElemStyle)
+        {
+            Boolean zoomok = isZoomOk(wayStyle);
+            Collection<Way> join = new LinkedList<Way>();
+
+            /* parse all outer rings and join them */
+            for (Way w : outer)
+            {
+                if(w.isClosed()) outerclosed.add(w);
+                else join.add(w);
+            }
+            if(join.size() != 0)
+            {
+                for(Way w : joinWays(join))
+                    outerclosed.add(w);
+            }
+
+            /* parse all inner rings and join them */
+            join.clear();
+            for (Way w : inner)
+            {
+                if(w.isClosed()) innerclosed.add(w);
+                else join.add(w);
+            }
+            if(join.size() != 0)
+            {
+                for(Way w : joinWays(join))
+                    innerclosed.add(w);
+            }
+
+            /* handle inside out stuff */
+
+            if(zoomok) /* draw */
+            {
+                for (Way w : outerclosed)
+                {
+                    Color color = w.selected ? selectedColor
+                    : ((AreaElemStyle)wayStyle).color;
+                    Polygon polygon = new Polygon();
+                    Point pOuter = null;
+
+                    for (Node n : w.nodes)
+                    {
+                        pOuter = nc.getPoint(n.eastNorth);
+                        polygon.addPoint(pOuter.x,pOuter.y);
+                    }
+                    for (Way wInner : innerclosed)
+                    {
+                        for (Node n : wInner.nodes)
+                        {
+                            Point pInner = nc.getPoint(n.eastNorth);
+                            polygon.addPoint(pInner.x,pInner.y);
+                        }
+                        polygon.addPoint(pOuter.x,pOuter.y);
+                    }
+
+                    g.setColor(new Color( color.getRed(), color.getGreen(),
+                    color.getBlue(), fillAlpha));
+
+                    g.fillPolygon(polygon);
+                    alreadyDrawnAreas.add(w);
+                }
+            }
+            for (Way wInner : inner)
+            {
+                ElemStyle innerStyle = styles.get(wInner);
+                if(innerStyle == null)
+                {
+                    if(zoomok)
+                        drawWay(wInner, ((AreaElemStyle)wayStyle).line,
+                        ((AreaElemStyle)wayStyle).color);
+                    alreadyDrawnWays.add(wInner);
+                }
+                else if(wayStyle.equals(innerStyle))
+                {
+System.out.println("WARNING: Inner waystyle equals multipolygon for way " + wInner);
+                    alreadyDrawnAreas.add(wInner);
+                }
+            }
+            for (Way wOuter : outer)
+            {
+                ElemStyle outerStyle = styles.get(wOuter);
+                if(outerStyle == null)
+                {
+                    if(zoomok)
+                        drawWay(wOuter, ((AreaElemStyle)wayStyle).line,
+                        ((AreaElemStyle)wayStyle).color);
+                    alreadyDrawnWays.add(wOuter);
+                }
+                else
+                {
+                    if(!wayStyle.equals(outerStyle))
+System.out.println("ERROR: Outer waystyle does not match multipolygon for way " + wOuter);
+                    alreadyDrawnAreas.add(wOuter);
+                }
+            }
+        }
+    }
+
     protected void drawWayAsArea(Way w, Color color)
     {
@@ -338,13 +586,30 @@
         regionalNameOrder = Main.pref.get("mappaint.nameOrder", "name:"+currentLocale+";name;int_name").split(";");
 
-        if (styles.hasAreas()) {
+        if (fillAreas && styles.hasAreas()) {
             Collection<Way> noAreaWays = new LinkedList<Way>();
 
-            for (final OsmPrimitive osm : data.ways)
-                if (!osm.incomplete && !osm.deleted && styles.isArea((Way)osm))
+            for (final Relation osm : data.relations)
+            {
+                if (!osm.deleted && !osm.selected)
+                {
                     osm.visit(this);
-                else if (!osm.deleted && !osm.incomplete)
-                    noAreaWays.add((Way)osm);
-
+                }
+            }
+
+            for (final Way osm : data.ways)
+            {
+                if (!osm.incomplete && !osm.deleted && !alreadyDrawnWays.contains(osm))
+                {
+                    if(styles.isArea((Way)osm) && !alreadyDrawnAreas.contains(osm))
+                        osm.visit(this);
+                    else
+                        noAreaWays.add((Way)osm);
+                }
+            }
+            // free that stuff
+            alreadyDrawnWays = null;
+            alreadyDrawnAreas = null;
+
+            fillAreas = false;
             for (final OsmPrimitive osm : noAreaWays)
                 osm.visit(this);
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyle.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyle.java	(revision 1189)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyle.java	(revision 1190)
@@ -8,4 +8,10 @@
 
     public int priority;
+    public String code;
+
+    public Boolean equals(ElemStyle s)
+    {
+        return s != null && s.code.equals(code);
+    }
 }
 
Index: /trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java	(revision 1189)
+++ /trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java	(revision 1190)
@@ -5,8 +5,11 @@
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 import java.util.Iterator;
 
 import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.OsmUtils;
+import org.openstreetmap.josm.data.osm.Relation;
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.Main;
@@ -46,20 +49,28 @@
     public void add(String name, String k, String v, String b, LineElemStyle style)
     {
-        getStyleSet(name, true).lines.put(getKey(k,v,b), style);
+        String key = getKey(k,v,b);
+        style.code = key;
+        getStyleSet(name, true).lines.put(key, style);
     }
 
     public void addModifier(String name, String k, String v, String b, LineElemStyle style)
     {
-        getStyleSet(name, true).modifiers.put(getKey(k,v,b), style);
+        String key = getKey(k,v,b);
+        style.code = key;
+        getStyleSet(name, true).modifiers.put(key, style);
     }
 
     public void add(String name, String k, String v, String b, AreaElemStyle style)
     {
-        getStyleSet(name, true).areas.put(getKey(k,v,b), style);
+        String key = getKey(k,v,b);
+        style.code = key;
+        getStyleSet(name, true).areas.put(key, style);
     }
 
     public void add(String name, String k, String v, String b, IconElemStyle style)
     {
-        getStyleSet(name, true).icons.put(getKey(k,v,b), style);
+        String key = getKey(k,v,b);
+        style.code = key;
+        getStyleSet(name, true).icons.put(key, style);
     }
 
@@ -109,18 +120,15 @@
     }
 
-    public ElemStyle get(Way w)
-    {
-        StyleSet ss = getStyleSet(null, false);
-        if(ss == null || w.keys == null)
-            return null;
+    private ElemStyle get(Map<String, String> keys, StyleSet ss)
+    {
         AreaElemStyle retArea = null;
         LineElemStyle retLine = null;
         String linestring = null;
         HashMap<String, LineElemStyle> over = new HashMap<String, LineElemStyle>();
-        Iterator<String> iterator = w.keys.keySet().iterator();
+        Iterator<String> iterator = keys.keySet().iterator();
         while(iterator.hasNext())
         {
             String key = iterator.next();
-            String val = w.keys.get(key);
+            String val = keys.get(key);
             AreaElemStyle styleArea;
             LineElemStyle styleLine;
@@ -173,22 +181,38 @@
     }
 
-    public boolean isArea(Way w)
-    {
-        StyleSet ss = getStyleSet(null, false);
-        if(ss != null && w.keys != null)
-        {
-            Iterator<String> iterator = w.keys.keySet().iterator();
-            while(iterator.hasNext())
-            {
-                String key = iterator.next();
-                String val = w.keys.get(key);
-                if(ss.areas.containsKey("n" + key + "=" + val)
-                || ss.areas.containsKey("n" + key + "=" + OsmUtils.getNamedOsmBoolean(val))
-                || ss.areas.containsKey("x" + key))
-                    return true;
-            }
+    public ElemStyle get(Way w)
+    {
+        StyleSet ss = getStyleSet(null, false);
+        return (ss == null || w.keys == null) ? null : get(w.keys, ss);
+    }
+
+    public ElemStyle get(Relation r)
+    {
+        StyleSet ss = getStyleSet(null, false);
+        return (ss == null || r.keys == null) ? null : get(r.keys, ss);
+    }
+
+    private boolean isArea(Map<String, String> keys, StyleSet ss)
+    {
+        Iterator<String> iterator = keys.keySet().iterator();
+        while(iterator.hasNext())
+        {
+            String key = iterator.next();
+            String val = keys.get(key);
+            if(ss.areas.containsKey("n" + key + "=" + val)
+            || ss.areas.containsKey("n" + key + "=" + OsmUtils.getNamedOsmBoolean(val))
+            || ss.areas.containsKey("x" + key))
+                return true;
         }
         return false;
     }
+
+    public boolean isArea(OsmPrimitive o)
+    {
+        StyleSet ss = getStyleSet(null, false);
+        return (ss != null && o.keys != null && !(o instanceof Node))
+        ? isArea(o.keys, ss) : false;
+    }
+
     public boolean hasAreas()
     {
