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 4629)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/relations/Multipolygon.java	(revision 4630)
@@ -10,14 +10,20 @@
 import java.util.Collection;
 import java.util.Collections;
+import java.util.HashSet;
+import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.Preferences.PreferenceChangeEvent;
 import org.openstreetmap.josm.data.Preferences.PreferenceChangedListener;
+import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
 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.event.NodeMovedEvent;
+import org.openstreetmap.josm.data.osm.event.WayNodesChangedEvent;
 import org.openstreetmap.josm.data.osm.visitor.paint.relations.Multipolygon.PolyData.Intersection;
 
@@ -150,8 +156,10 @@
     public static class JoinedWay {
         private final List<Node> nodes;
+        private final Collection<Long> wayIds;
         private final boolean selected;
 
-        public JoinedWay(List<Node> nodes, boolean selected) {
+        public JoinedWay(List<Node> nodes, Collection<Long> wayIds, boolean selected) {
             this.nodes = nodes;
+            this.wayIds = wayIds;
             this.selected = selected;
         }
@@ -161,4 +169,8 @@
         }
 
+        public Collection<Long> getWayIds() {
+            return wayIds;
+        }
+
         public boolean isSelected() {
             return selected;
@@ -173,18 +185,22 @@
         public enum Intersection {INSIDE, OUTSIDE, CROSSING}
 
-        public final Path2D.Double poly;
+        private final Path2D.Double poly;
         public boolean selected;
         private Rectangle2D bounds;
-        private final Collection<Way> ways;
+        private final Collection<Long> wayIds;
         private final List<Node> nodes;
         private final List<PolyData> inners;
 
-        public PolyData(JoinedWay joinedWay, Collection<Way> refWays) {
-            this(joinedWay.getNodes(), joinedWay.isSelected(), refWays);
-        }
-
-        public PolyData(List<Node> nodes, boolean selected, Collection<Way> refWays) {
-            this.ways = Collections.unmodifiableCollection(refWays);
-            this.nodes = Collections.unmodifiableList(nodes);
+        public PolyData(Way closedWay) {
+            this(closedWay.getNodes(), closedWay.isSelected(), Collections.singleton(closedWay.getId()));
+        }
+
+        public PolyData(JoinedWay joinedWay) {
+            this(joinedWay.getNodes(), joinedWay.isSelected(), joinedWay.getWayIds());
+        }
+
+        private PolyData(List<Node> nodes, boolean selected, Collection<Long> wayIds) {
+            this.wayIds = Collections.unmodifiableCollection(wayIds);
+            this.nodes = nodes;
             this.selected = selected;
             this.inners = new ArrayList<Multipolygon.PolyData>();
@@ -196,6 +212,5 @@
         private void buildPoly() {
             boolean initial = true;
-            for (Node n : nodes)
-            {
+            for (Node n : nodes) {
                 Point2D p = n.getEastNorth();
                 if (initial) {
@@ -215,6 +230,6 @@
             this.selected = copy.selected;
             this.poly = (Double) copy.poly.clone();
-            this.ways = Collections.unmodifiableCollection(copy.ways);
-            this.nodes = Collections.unmodifiableList(copy.nodes);
+            this.wayIds = Collections.unmodifiableCollection(copy.wayIds);
+            this.nodes = new ArrayList<Node>(copy.nodes);
             this.inners = new ArrayList<Multipolygon.PolyData>(copy.inners);
         }
@@ -259,6 +274,24 @@
         }
         
-        public Collection<Way> getWays() {
-            return ways;
+        public Collection<Long> getWayIds() {
+            return wayIds;
+        }
+        
+        private void resetNodes() {
+            if (!nodes.isEmpty()) {
+                DataSet ds = nodes.get(0).getDataSet();
+                nodes.clear();
+                if (wayIds.size() == 1) {
+                    Way w = (Way) ds.getPrimitiveById(wayIds.iterator().next(), OsmPrimitiveType.WAY);
+                    nodes.addAll(w.getNodes());
+                } else {
+                    List<Way> waysToJoin = new ArrayList<Way>();
+                    for (Iterator<Long> it = wayIds.iterator(); it.hasNext(); ) {
+                        waysToJoin.add((Way) ds.getPrimitiveById(it.next(), OsmPrimitiveType.WAY));
+                    }
+                    nodes.addAll(joinWays(waysToJoin).iterator().next().getNodes());
+                }
+                resetPoly();
+            }
         }
         
@@ -280,4 +313,18 @@
             if (nodes.contains(n) || innerChanged) {
                 resetPoly();
+            }
+        }
+        
+        public void wayNodesChanged(WayNodesChangedEvent event) {
+            final Long wayId = event.getChangedWay().getId();
+            boolean innerChanged = false;
+            for (PolyData inner : inners) {
+                if (inner.wayIds.contains(wayId)) {
+                    inner.resetNodes();
+                    innerChanged = true;
+                }
+            }
+            if (wayIds.contains(wayId) || innerChanged) {
+                resetNodes();
             }
         }
@@ -329,5 +376,5 @@
         for (Way way: ways) {
             if (way.isClosed()) {
-                result.add(new PolyData(way.getNodes(), way.isSelected(), Collections.singleton(way)));
+                result.add(new PolyData(way));
             } else {
                 waysToJoin.add(way);
@@ -336,88 +383,82 @@
 
         for (JoinedWay jw: joinWays(waysToJoin)) {
-            result.add(new PolyData(jw, waysToJoin));
-        }
-    }
-
-    public static Collection<JoinedWay> joinWays(Collection<Way> join)
+            result.add(new PolyData(jw));
+        }
+    }
+
+    public static Collection<JoinedWay> joinWays(Collection<Way> waysToJoin)
     {
-        Collection<JoinedWay> res = new ArrayList<JoinedWay>();
-        Way[] joinArray = join.toArray(new Way[join.size()]);
-        int left = join.size();
-        while(left != 0)
-        {
+        final Collection<JoinedWay> result = new ArrayList<JoinedWay>();
+        final Way[] joinArray = waysToJoin.toArray(new Way[waysToJoin.size()]);
+        int left = waysToJoin.size();
+        while (left > 0) {
             Way w = null;
             boolean selected = false;
-            List<Node> n = null;
+            List<Node> nodes = null;
+            Set<Long> wayIds = new HashSet<Long>();
             boolean joined = true;
-            while(joined && left != 0)
-            {
+            while (joined && left > 0) {
                 joined = false;
-                for(int i = 0; i < joinArray.length && left != 0; ++i)
-                {
-                    if(joinArray[i] != null)
-                    {
+                for (int i = 0; i < joinArray.length && left != 0; ++i) {
+                    if (joinArray[i] != null) {
                         Way c = joinArray[i];
-                        if(w == null)
-                        { w = c; selected = w.isSelected(); joinArray[i] = null; --left; }
-                        else
-                        {
+                        if (w == null) {
+                            w = c;
+                            selected = w.isSelected();
+                            joinArray[i] = null;
+                            --left;
+                        } else {
                             int mode = 0;
                             int cl = c.getNodesCount()-1;
                             int nl;
-                            if(n == null)
-                            {
+                            if (nodes == null) {
                                 nl = w.getNodesCount()-1;
-                                if(w.getNode(nl) == c.getNode(0)) {
+                                if (w.getNode(nl) == c.getNode(0)) {
                                     mode = 21;
-                                } else if(w.getNode(nl) == c.getNode(cl)) {
+                                } else if (w.getNode(nl) == c.getNode(cl)) {
                                     mode = 22;
-                                } else if(w.getNode(0) == c.getNode(0)) {
+                                } else if (w.getNode(0) == c.getNode(0)) {
                                     mode = 11;
-                                } else if(w.getNode(0) == c.getNode(cl)) {
+                                } else if (w.getNode(0) == c.getNode(cl)) {
                                     mode = 12;
                                 }
-                            }
-                            else
-                            {
-                                nl = n.size()-1;
-                                if(n.get(nl) == c.getNode(0)) {
+                            } else {
+                                nl = nodes.size()-1;
+                                if (nodes.get(nl) == c.getNode(0)) {
                                     mode = 21;
-                                } else if(n.get(0) == c.getNode(cl)) {
+                                } else if (nodes.get(0) == c.getNode(cl)) {
                                     mode = 12;
-                                } else if(n.get(0) == c.getNode(0)) {
+                                } else if (nodes.get(0) == c.getNode(0)) {
                                     mode = 11;
-                                } else if(n.get(nl) == c.getNode(cl)) {
+                                } else if (nodes.get(nl) == c.getNode(cl)) {
                                     mode = 22;
                                 }
                             }
-                            if(mode != 0)
-                            {
+                            if (mode != 0) {
                                 joinArray[i] = null;
                                 joined = true;
-                                if(c.isSelected()) {
+                                if (c.isSelected()) {
                                     selected = true;
                                 }
                                 --left;
-                                if(n == null) {
-                                    n = w.getNodes();
+                                if (nodes == null) {
+                                    nodes = w.getNodes();
+                                    wayIds.add(w.getId());
                                 }
-                                n.remove((mode == 21 || mode == 22) ? nl : 0);
-                                if(mode == 21) {
-                                    n.addAll(c.getNodes());
-                                } else if(mode == 12) {
-                                    n.addAll(0, c.getNodes());
-                                } else if(mode == 22)
-                                {
-                                    for(Node node : c.getNodes()) {
-                                        n.add(nl, node);
+                                nodes.remove((mode == 21 || mode == 22) ? nl : 0);
+                                if (mode == 21) {
+                                    nodes.addAll(c.getNodes());
+                                } else if (mode == 12) {
+                                    nodes.addAll(0, c.getNodes());
+                                } else if (mode == 22) {
+                                    for (Node node : c.getNodes()) {
+                                        nodes.add(nl, node);
+                                    }
+                                } else /* mode == 11 */ {
+                                    for (Node node : c.getNodes()) {
+                                        nodes.add(0, node);
                                     }
                                 }
-                                else /* mode == 11 */
-                                {
-                                    for(Node node : c.getNodes()) {
-                                        n.add(0, node);
-                                    }
-                                }
+                                wayIds.add(c.getId());
                             }
                         }
@@ -426,12 +467,13 @@
             } /* while(joined) */
 
-            if (n == null) {
-                n = w.getNodes();
-            }
-
-            res.add(new JoinedWay(n, selected));
+            if (nodes == null) {
+                nodes = w.getNodes();
+                wayIds.add(w.getId());
+            }
+
+            result.add(new JoinedWay(nodes, wayIds, selected));
         } /* while(left != 0) */
 
-        return res;
+        return result;
     }
 
@@ -521,4 +563,3 @@
         return combinedPolygons;
     }
-
 }
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 4629)
+++ trunk/src/org/openstreetmap/josm/data/osm/visitor/paint/relations/MultipolygonCache.java	(revision 4630)
@@ -120,16 +120,16 @@
     }
     
-    private final void updateMultipolygonsReferringTo(final AbstractDatasetChangedEvent event) {
+    private final void updateMultipolygonsReferringTo(AbstractDatasetChangedEvent event) {
         updateMultipolygonsReferringTo(event, event.getPrimitives(), event.getDataset());
     }
 
     private final void updateMultipolygonsReferringTo(
-            final AbstractDatasetChangedEvent event, final Collection<? extends OsmPrimitive> primitives, final DataSet ds) {
+            final AbstractDatasetChangedEvent event, Collection<? extends OsmPrimitive> primitives, DataSet ds) {
         updateMultipolygonsReferringTo(event, primitives, ds, null);
     }
     
     private final Collection<Map<Relation, Multipolygon>> updateMultipolygonsReferringTo(
-            final AbstractDatasetChangedEvent event, final Collection<? extends OsmPrimitive> primitives, 
-            final DataSet ds, final Collection<Map<Relation, Multipolygon>> initialMaps) {
+            AbstractDatasetChangedEvent event, Collection<? extends OsmPrimitive> primitives, 
+            DataSet ds, Collection<Map<Relation, Multipolygon>> initialMaps) {
         Collection<Map<Relation, Multipolygon>> maps = initialMaps;
         if (primitives != null) {
@@ -158,17 +158,33 @@
     }
     
-    private final void processEvent(final AbstractDatasetChangedEvent event, final Relation r, final Collection<Map<Relation, Multipolygon>> maps) {
-        if (event instanceof NodeMovedEvent) {
-            for (Map<Relation, Multipolygon> map : maps) {
-                Multipolygon m = map.get(r);
-                for (PolyData pd : m.getCombinedPolygons()) {
-                    pd.nodeMoved((NodeMovedEvent) event);
-                }
+    private final void processEvent(AbstractDatasetChangedEvent event, Relation r, Collection<Map<Relation, Multipolygon>> maps) {
+        if (event instanceof NodeMovedEvent || event instanceof WayNodesChangedEvent) {
+            dispatchEvent(event, r, maps);
+        } else if (event instanceof PrimitivesRemovedEvent) {
+            if (event.getPrimitives().contains(r)) {
+                removeMultipolygonFrom(r, maps);
             }
         } else {
             // Default (non-optimal) action: remove multipolygon from cache 
-            for (Map<Relation, Multipolygon> map : maps) {
-                map.remove(r);
-            }
+            removeMultipolygonFrom(r, maps);
+        }
+    }
+    
+    private final void dispatchEvent(AbstractDatasetChangedEvent event, Relation r, Collection<Map<Relation, Multipolygon>> maps) {
+        for (Map<Relation, Multipolygon> map : maps) {
+            Multipolygon m = map.get(r);
+            for (PolyData pd : m.getCombinedPolygons()) {
+                if (event instanceof NodeMovedEvent) {
+                    pd.nodeMoved((NodeMovedEvent) event);
+                } else if (event instanceof WayNodesChangedEvent) {
+                    pd.wayNodesChanged((WayNodesChangedEvent)event);
+                }
+            }
+        }
+    }
+    
+    private final void removeMultipolygonFrom(Relation r, Collection<Map<Relation, Multipolygon>> maps) {
+        for (Map<Relation, Multipolygon> map : maps) {
+            map.remove(r);
         }
     }
@@ -181,10 +197,10 @@
     @Override
     public void primitivesRemoved(PrimitivesRemovedEvent event) {
-        updateMultipolygonsReferringTo(event);// FIXME: See if it is possible to update only concerned PolyData
+        updateMultipolygonsReferringTo(event);
     }
 
     @Override
     public void tagsChanged(TagsChangedEvent event) {
-        //removeMultipolygonsReferringTo(event);
+        // Do nothing
     }
 
@@ -196,20 +212,20 @@
     @Override
     public void wayNodesChanged(WayNodesChangedEvent event) {
-        updateMultipolygonsReferringTo(event);// FIXME: See if it is possible to update only concerned PolyData
+        updateMultipolygonsReferringTo(event);
     }
 
     @Override
     public void relationMembersChanged(RelationMembersChangedEvent event) {
-        updateMultipolygonsReferringTo(event);// FIXME: See if it is possible to update only concerned PolyData
+        updateMultipolygonsReferringTo(event);
     }
 
     @Override
     public void otherDatasetChange(AbstractDatasetChangedEvent event) {
-        updateMultipolygonsReferringTo(event);// FIXME: See if it is possible to update only concerned PolyData
+        // Do nothing
     }
 
     @Override
     public void dataChanged(DataChangedEvent event) {
-        updateMultipolygonsReferringTo(event);// FIXME: See if it is possible to update only concerned PolyData
+        // Do nothing
     }
 
@@ -260,5 +276,5 @@
                             if (multipolygon != null) {
                                 for (PolyData pd : multipolygon.getCombinedPolygons()) {
-                                    if (pd.getWays().contains(p)) {
+                                    if (pd.getWayIds().contains(p.getId())) {
                                         pd.selected = true;
                                         selectedPolyData.add(pd);
