Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPainter.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPainter.java	(revision 4622)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/MapPainter.java	(revision 4623)
@@ -38,4 +38,5 @@
 import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon;
 import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon.PolyData;
+import org.openstreetmap.josm.data.osm.visitor.paint.relations.MultipolygonCache;
 import org.openstreetmap.josm.gui.NavigatableComponent;
 import org.openstreetmap.josm.gui.mappaint.BoxTextElemStyle;
@@ -860,6 +861,5 @@
 
     public void drawArea(Relation r, Color color, BufferedImage fillImage, float fillImageAlpha, TextElement text) {
-        Multipolygon multipolygon = new Multipolygon(nc);
-        multipolygon.load(r);
+        Multipolygon multipolygon = MultipolygonCache.getInstance().get(nc, r);
         if(!r.isDisabled() && !multipolygon.getOuterWays().isEmpty()) {
             for (PolyData pd : multipolygon.getCombinedPolygons()) {
Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/relations/Multipolygon.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/relations/Multipolygon.java	(revision 4622)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/relations/Multipolygon.java	(revision 4623)
@@ -134,5 +134,5 @@
      */
     private static MultipolygonRoleMatcher roleMatcher;
-    private static MultipolygonRoleMatcher getMultipoloygonRoleMatcher() {
+    private static MultipolygonRoleMatcher getMultipolygonRoleMatcher() {
         if (roleMatcher == null) {
             roleMatcher = new MultipolygonRoleMatcher();
@@ -237,6 +237,4 @@
     }
 
-    private final NavigatableComponent nc;
-
     private final List<Way> innerWays = new ArrayList<Way>();
     private final List<Way> outerWays = new ArrayList<Way>();
@@ -245,10 +243,10 @@
     private final List<PolyData> combinedPolygons = new ArrayList<PolyData>();
 
-    public Multipolygon(NavigatableComponent nc) {
-        this.nc = nc;
-    }
-
-    public void load(Relation r) {
-        MultipolygonRoleMatcher matcher = getMultipoloygonRoleMatcher();
+    public Multipolygon(NavigatableComponent nc, Relation r) {
+        load(r, nc);
+    }
+
+    private void load(Relation r, NavigatableComponent nc) {
+        MultipolygonRoleMatcher matcher = getMultipolygonRoleMatcher();
 
         // Fill inner and outer list with valid ways
@@ -273,6 +271,6 @@
         }
 
-        createPolygons(innerWays, innerPolygons);
-        createPolygons(outerWays, outerPolygons);
+        createPolygons(nc, innerWays, innerPolygons);
+        createPolygons(nc, outerWays, outerPolygons);
         if (!outerPolygons.isEmpty()) {
             addInnerToOuters();
@@ -280,5 +278,5 @@
     }
 
-    private void createPolygons(List<Way> ways, List<PolyData> result) {
+    private void createPolygons(NavigatableComponent nc, List<Way> ways, List<PolyData> result) {
         List<Way> waysToJoin = new ArrayList<Way>();
         for (Way way: ways) {
Index: trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/relations/MultipolygonCache.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/relations/MultipolygonCache.java	(revision 4623)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/relations/MultipolygonCache.java	(revision 4623)
@@ -0,0 +1,208 @@
+package org.openstreetmap.josm.data.osm.visitor.paint.relations;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.Way;
+import org.openstreetmap.josm.data.osm.event.AbstractDatasetChangedEvent;
+import org.openstreetmap.josm.data.osm.event.DataChangedEvent;
+import org.openstreetmap.josm.data.osm.event.DataSetListener;
+import org.openstreetmap.josm.data.osm.event.NodeMovedEvent;
+import org.openstreetmap.josm.data.osm.event.PrimitivesAddedEvent;
+import org.openstreetmap.josm.data.osm.event.PrimitivesRemovedEvent;
+import org.openstreetmap.josm.data.osm.event.RelationMembersChangedEvent;
+import org.openstreetmap.josm.data.osm.event.TagsChangedEvent;
+import org.openstreetmap.josm.data.osm.event.WayNodesChangedEvent;
+import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
+import org.openstreetmap.josm.gui.NavigatableComponent;
+import org.openstreetmap.josm.gui.NavigatableComponent.ZoomChangeListener;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+
+/*
+ * A memory cache for Multipolygon objects.
+ * 
+ */
+public class MultipolygonCache implements DataSetListener, LayerChangeListener, ZoomChangeListener {
+
+    private static final MultipolygonCache instance = new MultipolygonCache(); 
+    
+    private final Map<NavigatableComponent, Map<DataSet, Map<Relation, Multipolygon>>> cache;
+    
+    private MultipolygonCache() {
+        this.cache = new HashMap<NavigatableComponent, Map<DataSet, Map<Relation,Multipolygon>>>();
+    }
+
+    public static final MultipolygonCache getInstance() {
+        return instance;
+    }
+
+    public final Multipolygon get(NavigatableComponent nc, Relation r) {
+        Multipolygon multipolygon = null;
+        if (nc != null && r != null) {
+            Map<DataSet, Map<Relation, Multipolygon>> map1 = cache.get(nc);
+            if (map1 == null) {
+                cache.put(nc, map1 = new HashMap<DataSet, Map<Relation, Multipolygon>>());
+            }
+            Map<Relation, Multipolygon> map2 = map1.get(r.getDataSet());
+            if (map2 == null) {
+                map1.put(r.getDataSet(), map2 = new HashMap<Relation, Multipolygon>());
+            }
+            multipolygon = map2.get(r);
+            if (multipolygon == null) {
+                map2.put(r, multipolygon = new Multipolygon(nc, r));
+            }
+        }
+        return multipolygon;
+    }
+    
+    public final void clear(NavigatableComponent nc) {
+        Map<DataSet, Map<Relation, Multipolygon>> map = cache.remove(nc);
+        if (map != null) {
+            map.clear();
+            map = null;
+        }
+    }
+
+    public final void clear(DataSet ds) {
+        for (Map<DataSet, Map<Relation, Multipolygon>> map1 : cache.values()) {
+            Map<Relation, Multipolygon> map2 = map1.remove(ds);
+            if (map2 != null) {
+                map2.clear();
+                map2 = null;
+            }
+        }
+    }
+
+    public final void clear() {
+        cache.clear();
+    }
+    
+    private final Collection<Map<Relation, Multipolygon>> getMapsFor(DataSet ds) {
+        List<Map<Relation, Multipolygon>> result = new ArrayList<Map<Relation, Multipolygon>>();
+        for (Map<DataSet, Map<Relation, Multipolygon>> map : cache.values()) {
+            Map<Relation, Multipolygon> map2 = map.get(ds);
+            if (map2 != null) {
+                result.add(map2);
+            }
+        }
+        return result;
+    }
+    
+    private static final boolean isMultipolygon(OsmPrimitive p) {
+        return p instanceof Relation && ((Relation) p).isMultipolygon();
+    }
+    
+    private static final void removeMultipolygonFrom(Relation mp, Collection<Map<Relation, Multipolygon>> maps) {
+        for (Map<Relation, Multipolygon> map : maps) {
+            map.remove(mp);
+        }
+    }
+
+    private final void removeMultipolygonsReferringTo(AbstractDatasetChangedEvent event) {
+        removeMultipolygonsReferringTo(event.getPrimitives(), event.getDataset());
+    }
+
+    private final void removeMultipolygonsReferringTo(Collection<? extends OsmPrimitive> primitives, DataSet ds) {
+        removeMultipolygonsReferringTo(primitives, ds, null);
+    }
+    
+    private final Collection<Map<Relation, Multipolygon>> removeMultipolygonsReferringTo(
+            Collection<? extends OsmPrimitive> primitives, DataSet ds, Collection<Map<Relation, Multipolygon>> initialMaps) {
+        Collection<Map<Relation, Multipolygon>> maps = initialMaps;
+        if (primitives != null) {
+            for (OsmPrimitive p : primitives) {
+                if (isMultipolygon(p)) {
+                    if (maps == null) {
+                        maps = getMapsFor(ds);
+                    }
+                    removeMultipolygonFrom((Relation) p, maps);
+                    
+                } else if (p instanceof Way) {
+                    for (OsmPrimitive ref : p.getReferrers()) {
+                        if (isMultipolygon(ref)) {
+                            if (maps == null) {
+                                maps = getMapsFor(ds);
+                            }
+                            removeMultipolygonFrom((Relation) ref, maps);
+                        }
+                    }
+                } else if (p instanceof Node) {
+                    maps = removeMultipolygonsReferringTo(p.getReferrers(), ds, maps);
+                }
+            }
+        }
+        return maps;
+    }
+
+    @Override
+    public void primitivesAdded(PrimitivesAddedEvent event) {
+        // Do nothing
+    }
+
+    @Override
+    public void primitivesRemoved(PrimitivesRemovedEvent event) {
+        removeMultipolygonsReferringTo(event);
+    }
+
+    @Override
+    public void tagsChanged(TagsChangedEvent event) {
+        removeMultipolygonsReferringTo(event);
+    }
+
+    @Override
+    public void nodeMoved(NodeMovedEvent event) {
+        removeMultipolygonsReferringTo(event);
+    }
+
+    @Override
+    public void wayNodesChanged(WayNodesChangedEvent event) {
+        removeMultipolygonsReferringTo(event);
+    }
+
+    @Override
+    public void relationMembersChanged(RelationMembersChangedEvent event) {
+        removeMultipolygonsReferringTo(event);
+    }
+
+    @Override
+    public void otherDatasetChange(AbstractDatasetChangedEvent event) {
+        removeMultipolygonsReferringTo(event);
+    }
+
+    @Override
+    public void dataChanged(DataChangedEvent event) {
+        removeMultipolygonsReferringTo(event);
+    }
+
+    @Override
+    public void activeLayerChange(Layer oldLayer, Layer newLayer) {
+        // Do nothing
+    }
+
+    @Override
+    public void layerAdded(Layer newLayer) {
+        // Do nothing
+    }
+
+    @Override
+    public void layerRemoved(Layer oldLayer) {
+        if (oldLayer instanceof OsmDataLayer) {
+            clear(((OsmDataLayer) oldLayer).data);
+        }
+    }
+
+    @Override
+    public void zoomChanged(/*NavigatableComponent source*/) {
+        // TODO Change zoomChanged() method to add a "NavigatableComponent source" argument ? (this method is however used at least by one plugin)
+        //clear(source);
+        clear();
+    }
+}
Index: trunk/src/org/openstreetmap/josm/data/validation/tests/MultipolygonTest.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/validation/tests/MultipolygonTest.java	(revision 4622)
+++ trunk/src/org/openstreetmap/josm/data/validation/tests/MultipolygonTest.java	(revision 4623)
@@ -134,6 +134,5 @@
             checkMembersAndRoles(r);
 
-            Multipolygon polygon = new Multipolygon(Main.map.mapView);
-            polygon.load(r);
+            Multipolygon polygon = new Multipolygon(Main.map.mapView, r);
 
             boolean hasOuterWay = false;
Index: trunk/src/org/openstreetmap/josm/gui/MapView.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MapView.java	(revision 4622)
+++ trunk/src/org/openstreetmap/josm/gui/MapView.java	(revision 4623)
@@ -45,4 +45,5 @@
 import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
 import org.openstreetmap.josm.data.osm.visitor.paint.PaintColors;
+import org.openstreetmap.josm.data.osm.visitor.paint.relations.MultipolygonCache;
 import org.openstreetmap.josm.gui.layer.GpxLayer;
 import org.openstreetmap.josm.gui.layer.Layer;
@@ -51,5 +52,4 @@
 import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer;
 import org.openstreetmap.josm.gui.layer.markerlayer.PlayHeadMarker;
-import org.openstreetmap.josm.gui.mappaint.MapPaintStyles;
 import org.openstreetmap.josm.tools.AudioPlayer;
 import org.openstreetmap.josm.tools.BugReportExceptionHandler;
@@ -238,4 +238,8 @@
             }
         });
+        
+        // Add Multipolygon cache to layer and zoom listeners
+        addLayerChangeListener(MultipolygonCache.getInstance());
+        addZoomChangeListener(MultipolygonCache.getInstance());
     }
 
@@ -843,5 +847,5 @@
         Main.pref.removePreferenceChangeListener(this);
         DataSet.removeSelectionListener(repaintSelectionChangedListener);
-        MapPaintStyles.getStyles().clearMultipolygonsCache(this);
+        MultipolygonCache.getInstance().clear(this);
     }
 
Index: trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 4622)
+++ trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 4623)
@@ -63,4 +63,5 @@
 import org.openstreetmap.josm.data.osm.visitor.paint.MapRendererFactory;
 import org.openstreetmap.josm.data.osm.visitor.paint.Rendering;
+import org.openstreetmap.josm.data.osm.visitor.paint.relations.MultipolygonCache;
 import org.openstreetmap.josm.data.projection.Projection;
 import org.openstreetmap.josm.data.validation.TestError;
@@ -207,4 +208,5 @@
         conflicts = new ConflictCollection();
         data.addDataSetListener(new DataSetListenerAdapter(this));
+        data.addDataSetListener(MultipolygonCache.getInstance());
         DataSet.addSelectionListener(this);
     }
Index: trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java	(revision 4622)
+++ trunk/src/org/openstreetmap/josm/gui/mappaint/ElemStyles.java	(revision 4623)
@@ -6,8 +6,6 @@
 import java.util.Collection;
 import java.util.Collections;
-import java.util.HashMap;
 import java.util.Iterator;
 import java.util.List;
-import java.util.Map;
 import java.util.Map.Entry;
 
@@ -17,4 +15,5 @@
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon;
+import org.openstreetmap.josm.data.osm.visitor.paint.relations.MultipolygonCache;
 import org.openstreetmap.josm.gui.NavigatableComponent;
 import org.openstreetmap.josm.gui.mappaint.StyleCache.StyleList;
@@ -31,10 +30,7 @@
     private int defaultNodesIdx, defaultLinesIdx;
     
-    private final Map<NavigatableComponent, Map<Relation, Multipolygon>> multipolygonsCache;
-
     public ElemStyles()
     {
         styleSources = new ArrayList<StyleSource>();
-        multipolygonsCache = new HashMap<NavigatableComponent, Map<Relation,Multipolygon>>();
     }
 
@@ -121,18 +117,4 @@
     }
 
-    private final Multipolygon getCachedMultipolygon(NavigatableComponent nc, Relation r) {
-        Multipolygon multipolygon = null;
-        Map<Relation, Multipolygon> map = multipolygonsCache.get(nc);
-        if (map == null) {
-            multipolygonsCache.put(nc, map = new HashMap<Relation, Multipolygon>());
-        }
-        multipolygon = map.get(r);
-        if (multipolygon == null) {
-            map.put(r, multipolygon = new Multipolygon(nc));
-            multipolygon.load(r);
-        }
-        return multipolygon;
-    }
-    
     /**
      * Create the list of styles and its valid scale range for one primitive.
@@ -179,5 +161,5 @@
                     continue;
                 }
-                Multipolygon multipolygon = getCachedMultipolygon(nc, r);
+                Multipolygon multipolygon = MultipolygonCache.getInstance().get(nc, r);
 
                 if (multipolygon.getOuterWays().contains(osm)) {
@@ -244,5 +226,5 @@
                     continue;
                 }
-                final Multipolygon multipolygon = getCachedMultipolygon(nc, ref);
+                final Multipolygon multipolygon = MultipolygonCache.getInstance().get(nc, ref);
 
                 if (multipolygon.getInnerWays().contains(osm)) {
@@ -277,6 +259,5 @@
                 if (!Utils.exists(p.a, AreaElemStyle.class)) {
                     // look at outer ways to find area style
-                    Multipolygon multipolygon = new Multipolygon(nc);
-                    multipolygon.load((Relation) osm);
+                    Multipolygon multipolygon = MultipolygonCache.getInstance().get(nc, (Relation) osm);
                     for (Way w : multipolygon.getOuterWays()) {
                         Pair<StyleList, Range> wayStyles = generateStyles(w, scale, null, false);
@@ -429,7 +410,3 @@
         styleSources.addAll(sources);
     }
-
-    public void clearMultipolygonsCache(NavigatableComponent nc) {
-        multipolygonsCache.remove(nc);
-    }
 }
