Index: /trunk/images_nodist/multipoly_create.svg
===================================================================
--- /trunk/images_nodist/multipoly_create.svg	(revision 3704)
+++ /trunk/images_nodist/multipoly_create.svg	(revision 3704)
@@ -0,0 +1,198 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+   xmlns:dc="http://purl.org/dc/elements/1.1/"
+   xmlns:cc="http://creativecommons.org/ns#"
+   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+   xmlns:svg="http://www.w3.org/2000/svg"
+   xmlns="http://www.w3.org/2000/svg"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   width="48"
+   height="48"
+   id="svg2"
+   version="1.1"
+   inkscape:version="0.47pre4 r22446"
+   inkscape:export-xdpi="45"
+   inkscape:export-ydpi="45"
+   sodipodi:docname="multipoly_create.svg">
+  <defs
+     id="defs4">
+    <inkscape:perspective
+       sodipodi:type="inkscape:persp3d"
+       inkscape:vp_x="0 : 526.18109 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_z="744.09448 : 526.18109 : 1"
+       inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+       id="perspective10" />
+    <inkscape:perspective
+       id="perspective3602"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 0.5 : 1"
+       sodipodi:type="inkscape:persp3d" />
+    <inkscape:perspective
+       id="perspective3602-6"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 0.5 : 1"
+       sodipodi:type="inkscape:persp3d" />
+    <inkscape:perspective
+       id="perspective3602-65"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 0.5 : 1"
+       sodipodi:type="inkscape:persp3d" />
+    <inkscape:perspective
+       id="perspective3602-3"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 0.5 : 1"
+       sodipodi:type="inkscape:persp3d" />
+    <inkscape:perspective
+       id="perspective3677"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 0.5 : 1"
+       sodipodi:type="inkscape:persp3d" />
+    <inkscape:perspective
+       id="perspective3677-9"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 0.5 : 1"
+       sodipodi:type="inkscape:persp3d" />
+    <inkscape:perspective
+       id="perspective3677-90"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 0.5 : 1"
+       sodipodi:type="inkscape:persp3d" />
+    <inkscape:perspective
+       id="perspective3721"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 0.5 : 1"
+       sodipodi:type="inkscape:persp3d" />
+    <inkscape:perspective
+       id="perspective3643"
+       inkscape:persp3d-origin="0.5 : 0.33333333 : 1"
+       inkscape:vp_z="1 : 0.5 : 1"
+       inkscape:vp_y="0 : 1000 : 0"
+       inkscape:vp_x="0 : 0.5 : 1"
+       sodipodi:type="inkscape:persp3d" />
+  </defs>
+  <sodipodi:namedview
+     id="base"
+     pagecolor="#ffffff"
+     bordercolor="#666666"
+     borderopacity="1.0"
+     inkscape:pageopacity="0.0"
+     inkscape:pageshadow="2"
+     inkscape:zoom="2.8284271"
+     inkscape:cx="46.704094"
+     inkscape:cy="6.4355647"
+     inkscape:document-units="px"
+     inkscape:current-layer="layer1"
+     showgrid="true"
+     inkscape:window-width="683"
+     inkscape:window-height="476"
+     inkscape:window-x="582"
+     inkscape:window-y="210"
+     inkscape:window-maximized="0">
+    <inkscape:grid
+       type="xygrid"
+       id="grid3592"
+       empspacing="5"
+       visible="true"
+       enabled="true"
+       snapvisiblegridlinesonly="true" />
+  </sodipodi:namedview>
+  <metadata
+     id="metadata7">
+    <rdf:RDF>
+      <cc:Work
+         rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type
+           rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+        <dc:title></dc:title>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <g
+     inkscape:label="Layer 1"
+     inkscape:groupmode="layer"
+     id="layer1"
+     transform="translate(10.9,-1015.2622)">
+    <path
+       style="fill:#0000ff;fill-opacity:0.42180094000000001;stroke:#1919ff;stroke-width:1.30000000000000004;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;marker-mid:none"
+       d="m 14,1020.3623 -16,4 -6,36 40,-6 0,-24 -18,-10 z m -4,14 12,4 -14,10 2,-14 z"
+       id="path3667" />
+    <rect
+       style="fill:#fefefe;fill-opacity:1;stroke:#de0000;stroke-width:1.79999994999999990;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;color:#000000;fill-rule:nonzero;stroke-linecap:butt;stroke-linejoin:miter;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+       id="rect2816"
+       width="4"
+       height="4"
+       x="-3.9000001"
+       y="1022.2622" />
+    <rect
+       style="fill:#fefefe;fill-opacity:1;stroke:#de0000;stroke-width:1.79999994999999990;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;color:#000000;fill-rule:nonzero;stroke-linecap:butt;stroke-linejoin:miter;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+       id="rect2816-7"
+       width="4"
+       height="4"
+       x="12"
+       y="1018.3622" />
+    <rect
+       style="fill:#fefefe;fill-opacity:1;stroke:#de0000;stroke-width:1.79999994999999990;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+       id="rect2816-73"
+       width="4"
+       height="4"
+       x="30"
+       y="1028.3622" />
+    <rect
+       style="fill:#fefefe;fill-opacity:1;stroke:#de0000;stroke-width:1.79999994999999990;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;color:#000000;fill-rule:nonzero;stroke-linecap:butt;stroke-linejoin:miter;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+       id="rect2816-6"
+       width="4"
+       height="4"
+       x="30"
+       y="1050.3622" />
+    <rect
+       style="fill:#fefefe;fill-opacity:1;stroke:#de0000;stroke-width:1.79999994999999990;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;color:#000000;fill-rule:nonzero;stroke-linecap:butt;stroke-linejoin:miter;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+       id="rect2816-9"
+       width="4"
+       height="4"
+       x="-10"
+       y="1058.3622"
+       ry="0" />
+    <rect
+       style="fill:#fefefe;fill-opacity:1;stroke:#de0000;stroke-width:1.79999994999999990;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;color:#000000;fill-rule:nonzero;stroke-linecap:butt;stroke-linejoin:miter;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+       id="rect2816-7-2"
+       width="4"
+       height="4"
+       x="20"
+       y="1036.3622" />
+    <rect
+       style="fill:#fefefe;fill-opacity:1;stroke:#de0000;stroke-width:1.79999994999999990;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;color:#000000;fill-rule:nonzero;stroke-linecap:butt;stroke-linejoin:miter;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+       id="rect2816-7-3"
+       width="4"
+       height="4"
+       x="8"
+       y="1032.3622" />
+    <rect
+       style="fill:#fefefe;fill-opacity:1;stroke:#de0000;stroke-width:1.79999994999999990;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;color:#000000;fill-rule:nonzero;stroke-linecap:butt;stroke-linejoin:miter;stroke-dashoffset:0;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate"
+       id="rect2816-7-8"
+       width="4"
+       height="4"
+       x="6"
+       y="1046.3622" />
+  </g>
+</svg>
Index: /trunk/src/org/openstreetmap/josm/actions/CreateMultipolygonAction.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/actions/CreateMultipolygonAction.java	(revision 3704)
+++ /trunk/src/org/openstreetmap/josm/actions/CreateMultipolygonAction.java	(revision 3704)
@@ -0,0 +1,226 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.actions;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.swing.JOptionPane;
+
+import javax.swing.SwingUtilities;
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.command.AddCommand;
+import org.openstreetmap.josm.command.ChangePropertyCommand;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.command.SequenceCommand;
+import org.openstreetmap.josm.data.osm.MultipolygonCreate;
+import org.openstreetmap.josm.data.osm.MultipolygonCreate.JoinedPolygon;
+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.gui.dialogs.relation.RelationEditor;
+import org.openstreetmap.josm.tools.Shortcut;
+
+/**
+ * Create multipolygon from selected ways automatically.
+ *
+ * New relation with type=multipolygon is created
+ *
+ * If one or more of ways is already in relation with type=multipolygon or the
+ * way is not closed, then error is reported and no relation is created
+ *
+ * The "inner" and "outer" roles are guessed automatically. First, bbox is
+ * calculated for each way. then the largest area is assumed to be outside and
+ * the rest inside. In cases with one "outside" area and several cut-ins, the
+ * guess should be always good ... In more complex (multiple outer areas) or
+ * buggy (inner and outer ways intersect) scenarios the result is likely to be
+ * wrong.
+ */
+public class CreateMultipolygonAction extends JosmAction {
+
+    public CreateMultipolygonAction() {
+        super(tr("Create multipolygon"), "multipoly_create", tr("Create multipolygon."),
+                Shortcut.registerShortcut("tools:multipoly", tr("Tool: {0}", tr("Create multipolygon")),
+                        KeyEvent.VK_A, Shortcut.GROUP_EDIT, Shortcut.SHIFT_DEFAULT), true);
+    }
+    /**
+     * The action button has been clicked
+     *
+     * @param e Action Event
+     */
+    public void actionPerformed(ActionEvent e) {
+        if (Main.main.getEditLayer() == null) {
+            JOptionPane.showMessageDialog(Main.parent, tr("No data loaded."));
+            return;
+        }
+
+        Collection<Way> selectedWays = Main.main.getCurrentDataSet().getSelectedWays();
+
+        if (selectedWays.size() < 1) {
+            // Sometimes it make sense creating multipoly of only one way (so it will form outer way)
+            // and then splitting the way later (so there are multiple ways forming outer way)
+            JOptionPane.showMessageDialog(Main.parent, tr("You must select at least one way."));
+            return;
+        }
+
+        MultipolygonCreate polygon = this.analyzeWays(selectedWays);
+
+        if (polygon == null)
+            return;                   //could not make multipolygon.
+
+        final Relation relation = this.createRelation(polygon);
+
+        if (Main.pref.getBoolean("multipoly.show-relation-editor", false)) {
+            //Open relation edit window, if set up in preferences
+            RelationEditor editor = RelationEditor.getEditor(Main.main.getEditLayer(), relation, null);
+
+            editor.setModal(true);
+            editor.setVisible(true);
+
+            //TODO: cannot get the resulting relation from RelationEditor :(.
+            /*
+            if (relationCountBefore < relationCountAfter) {
+                //relation saved, clean up the tags
+                List<Command> list = this.removeTagsFromInnerWays(relation);
+                if (list.size() > 0)
+                {
+                    Main.main.undoRedo.add(new SequenceCommand(tr("Remove tags from multipolygon inner ways"), list));
+                }
+            }
+             */
+
+        } else {
+            //Just add the relation
+            List<Command> list = this.removeTagsFromInnerWays(relation);
+            list.add(new AddCommand(relation));
+            Main.main.undoRedo.add(new SequenceCommand(tr("Create multipolygon"), list));
+            Main.map.relationListDialog.unfurlDialog();
+            // Use 'SwingUtilities.invokeLater' to make sure the relationListDialog
+            // knows about the new relation before we try to select it.
+            // (Yes, we are already in event dispatch thread. But DatasetEventManager
+            // uses 'SwingUtilities.invokeLater' to fire events so we have to do
+            // the same.)
+            SwingUtilities.invokeLater(new Runnable() {
+                public void run() {
+                    Main.map.relationListDialog.selectRelation(relation);
+                }
+            });
+        }
+
+
+    }
+
+    /** Enable this action only if something is selected */
+    @Override protected void updateEnabledState() {
+        if (getCurrentDataSet() == null) {
+            setEnabled(false);
+        } else {
+            updateEnabledState(getCurrentDataSet().getSelected());
+        }
+    }
+
+    /** Enable this action only if something is selected */
+    @Override protected void updateEnabledState(Collection < ? extends OsmPrimitive > selection) {
+        setEnabled(selection != null && !selection.isEmpty());
+    }
+
+    /**
+     * This method analyzes ways and creates multipolygon.
+     * @param selectedWays
+     * @return null, if there was a problem with the ways.
+     */
+    private MultipolygonCreate analyzeWays(Collection < Way > selectedWays) {
+
+        MultipolygonCreate pol = new MultipolygonCreate();
+        String error = pol.makeFromWays(selectedWays);
+
+        if (error != null) {
+            JOptionPane.showMessageDialog(Main.parent, error);
+            return null;
+        } else {
+            return pol;
+        }
+    }
+
+    /**
+     * Builds a relation from polygon ways.
+     * @param pol
+     * @return
+     */
+    private Relation createRelation(MultipolygonCreate pol) {
+        // Create new relation
+        Relation rel = new Relation();
+        rel.put("type", "multipolygon");
+        // Add ways to it
+        for (JoinedPolygon jway:pol.outerWays) {
+            for (Way way:jway.ways) {
+                rel.addMember(new RelationMember("outer", way));
+            }
+        }
+
+        for (JoinedPolygon jway:pol.innerWays) {
+            for (Way way:jway.ways) {
+                rel.addMember(new RelationMember("inner", way));
+            }
+        }
+        return rel;
+    }
+
+    /**
+     * This method removes tags/value pairs from inner ways that are present in relation or outer ways.
+     * @param relation
+     */
+    private List<Command> removeTagsFromInnerWays(Relation relation) {
+        Map<String, String> values = new HashMap<String, String>();
+
+        if (relation.hasKeys()){
+            for(String key: relation.keySet()) {
+                values.put(key, relation.get(key));
+            }
+        }
+
+        List<Way> innerWays = new ArrayList<Way>();
+
+        for (RelationMember m: relation.getMembers()) {
+
+            if (m.hasRole() && m.getRole() == "inner" && m.isWay() && m.getWay().hasKeys()) {
+                innerWays.add(m.getWay());
+            }
+
+            if (m.hasRole() && m.getRole() == "outer" && m.isWay() && m.getWay().hasKeys()) {
+                Way way = m.getWay();
+                for (String key: way.keySet()) {
+                    if (!values.containsKey(key)) { //relation values take precedence
+                        values.put(key, way.get(key));
+                    }
+                }
+            }
+        }
+
+        List<Command> commands = new ArrayList<Command>();
+
+        for(String key: values.keySet()) {
+            List<OsmPrimitive> affectedWays = new ArrayList<OsmPrimitive>();
+            String value = values.get(key);
+
+            for (Way way: innerWays) {
+                if (value.equals(way.get(key))) {
+                    affectedWays.add(way);
+                }
+            }
+
+            if (affectedWays.size() > 0) {
+                commands.add(new ChangePropertyCommand(affectedWays, key, null));
+            }
+        }
+
+        return commands;
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/data/osm/MultipolygonCreate.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/MultipolygonCreate.java	(revision 3704)
+++ /trunk/src/org/openstreetmap/josm/data/osm/MultipolygonCreate.java	(revision 3704)
@@ -0,0 +1,277 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.osm;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.openstreetmap.josm.tools.Geometry;
+import org.openstreetmap.josm.tools.Geometry.PolygonIntersection;
+import org.openstreetmap.josm.tools.MultiMap;
+
+public class MultipolygonCreate {
+
+    /**
+     * Represents one polygon that consists of multiple ways.
+     * @author Viesturs
+     *
+     */
+    public static class JoinedPolygon {
+        public final List<Way> ways;
+        public final List<Boolean> reversed;
+        public final List<Node> nodes;
+
+        public JoinedPolygon(List<Way> ways, List<Boolean> reversed) {
+            this.ways = ways;
+            this.reversed = reversed;
+            this.nodes = this.getNodes();
+        }
+
+        /**
+         * Creates a polygon from single way.
+         * @param way
+         */
+        public JoinedPolygon(Way way) {
+            this.ways = Collections.singletonList(way);
+            this.reversed = Collections.singletonList(Boolean.FALSE);
+            this.nodes = this.getNodes();
+        }
+
+
+        /**
+         * Builds a list of nodes for this polygon. First node is not duplicated as last node.
+         * @return
+         */
+        private List<Node> getNodes() {
+            List<Node> nodes = new ArrayList<Node>();
+
+            for(int waypos = 0; waypos < this.ways.size(); waypos ++) {
+                Way way = this.ways.get(waypos);
+                boolean reversed = this.reversed.get(waypos).booleanValue();
+
+                if (!reversed){
+                    for (int pos = 0; pos < way.getNodesCount() - 1; pos++) {
+                        nodes.add(way.getNode(pos));
+                    }
+                }
+                else {
+                    for (int pos = way.getNodesCount() - 1; pos > 0; pos--) {
+                        nodes.add(way.getNode(pos));
+                    }
+                }
+            }
+
+            return nodes;
+        }
+    }
+
+
+    /**
+     * Helper storage class for finding findOuterWays
+     * @author viesturs
+     */
+    static class PolygonLevel {
+        public final int level; //nesting level , even for outer, odd for inner polygons.
+        public final JoinedPolygon outerWay;
+
+        public List<JoinedPolygon> innerWays;
+
+        public PolygonLevel(JoinedPolygon _pol, int _level) {
+            this.outerWay = _pol;
+            this.level = _level;
+            this.innerWays = new ArrayList<JoinedPolygon>();
+        }
+    }
+
+    public List<JoinedPolygon> outerWays;
+    public List<JoinedPolygon> innerWays;
+
+    public MultipolygonCreate(List<JoinedPolygon> outerWays, List<JoinedPolygon> innerWays){
+        this.outerWays = outerWays;
+        this.innerWays = innerWays;
+    }
+
+    public MultipolygonCreate(){
+        this.outerWays = new ArrayList<JoinedPolygon>(0);
+        this.innerWays = new ArrayList<JoinedPolygon>(0);
+    }
+
+    /**
+     * Splits ways into inner and outer JoinedWays. Sets innerWays and outerWays to the result.
+     *  TODO: Currently cannot process touching polygons. See code in JoinAreasAction.
+     * @return error description if the ways cannot be split. Null if all fine.
+     */
+    public String makeFromWays(Collection<Way> ways){
+        List<JoinedPolygon> joinedWays = new ArrayList<JoinedPolygon>();
+
+        //collect ways connecting to each node.
+        MultiMap<Node, Way> nodesWithConnectedWays = new MultiMap<Node, Way>();
+        Set<Way> usedWays = new HashSet<Way>();
+
+        for(Way w: ways) {
+            if (w.getNodesCount() < 2) {
+                return tr("Cannot add a way with only {0} nodes.", w.getNodesCount());
+            }
+
+            if (w.isClosed()) {
+                //closed way, add as is.
+                JoinedPolygon jw = new JoinedPolygon(w);
+                joinedWays.add(jw);
+                usedWays.add(w);
+            }
+            else {
+                nodesWithConnectedWays.put(w.lastNode(), w);
+                nodesWithConnectedWays.put(w.firstNode(), w);
+            }
+        }
+
+        //process unclosed ways
+        for (Way startWay: ways) {
+            if (usedWays.contains(startWay)){
+                continue;
+            }
+
+            Node startNode = startWay.firstNode();
+            List<Way> collectedWays = new ArrayList<Way>();
+            List<Boolean> collectedWaysReverse = new ArrayList<Boolean>();
+            Way curWay = startWay;
+            Node prevNode = startNode;
+
+            //find polygon ways
+            while (true) {
+                boolean curWayReverse = prevNode == curWay.lastNode();
+                Node nextNode = (curWayReverse) ? curWay.firstNode(): curWay.lastNode();
+
+                //add cur way to the list
+                collectedWays.add(curWay);
+                collectedWaysReverse.add(Boolean.valueOf(curWayReverse));
+
+                if (nextNode == startNode) {
+                    //way finished
+                    break;
+                }
+
+                //find next way
+                Collection<Way> adjacentWays = nodesWithConnectedWays.get(nextNode);
+
+                if (adjacentWays.size() != 2) {
+                    return tr("Each node must connect exactly 2 ways");
+                }
+
+                Way nextWay = null;
+                for(Way way: adjacentWays){
+                    if (way != curWay){
+                        nextWay = way;
+                    }
+                }
+
+                //move to the next way
+                curWay = nextWay;
+                prevNode = nextNode;
+            }
+
+            usedWays.addAll(collectedWays);
+            joinedWays.add(new JoinedPolygon(collectedWays, collectedWaysReverse));
+        }
+
+        //analyze witch way is inside witch outside.
+        return makeFromPolygons(joinedWays);
+    }
+
+    /**
+     * This method analyzes which ways are inner and which outer. Sets innerWays and outerWays to the result.
+     * @param joinedWays
+     * @return error description if the ways cannot be split. Null if all fine.
+     */
+    private String makeFromPolygons(List<JoinedPolygon> polygons) {
+        List<PolygonLevel> list = findOuterWaysRecursive(0, polygons);
+
+        if (list == null){
+            return tr("There is an intersection between ways.");
+        }
+
+        this.outerWays = new ArrayList<JoinedPolygon>(0);
+        this.innerWays = new ArrayList<JoinedPolygon>(0);
+
+        //take every other level
+        for (PolygonLevel pol : list) {
+            if (pol.level % 2 == 0) {
+                this.outerWays.add(pol.outerWay);
+            }
+            else {
+                this.innerWays.add(pol.outerWay);
+            }
+        }
+
+        return null;
+    }
+
+    /**
+     * Collects outer way and corresponding inner ways from all boundaries.
+     * @param boundaryWays
+     * @return the outermostWay, or null if intersection found.
+     */
+    private List<PolygonLevel> findOuterWaysRecursive(int level, Collection<JoinedPolygon> boundaryWays) {
+
+        //TODO: bad performance for deep nesting...
+        List<PolygonLevel> result = new ArrayList<PolygonLevel>();
+
+        for (JoinedPolygon outerWay : boundaryWays) {
+
+            boolean outerGood = true;
+            List<JoinedPolygon> innerCandidates = new ArrayList<JoinedPolygon>();
+
+            for (JoinedPolygon innerWay : boundaryWays) {
+                if (innerWay == outerWay) {
+                    continue;
+                }
+
+                PolygonIntersection intersection = Geometry.polygonIntersection(outerWay.nodes, innerWay.nodes);
+
+                if (intersection == PolygonIntersection.FIRST_INSIDE_SECOND) {
+                    outerGood = false;  // outer is inside another polygon
+                    break;
+                } else if (intersection == PolygonIntersection.SECOND_INSIDE_FIRST) {
+                    innerCandidates.add(innerWay);
+                }
+                else if (intersection == PolygonIntersection.CROSSING)
+                {
+                    //ways intersect
+                    return null;
+                }
+            }
+
+            if (!outerGood) {
+                continue;
+            }
+
+            //add new outer polygon
+            PolygonLevel pol = new PolygonLevel(outerWay, level);
+
+            //process inner ways
+            if (innerCandidates.size() > 0) {
+                List<PolygonLevel> innerList = this.findOuterWaysRecursive(level + 1, innerCandidates);
+                if (innerList == null) {
+                    return null; //intersection found
+                }
+
+                result.addAll(innerList);
+
+                for (PolygonLevel pl : innerList) {
+                    if (pl.level == level + 1) {
+                        pol.innerWays.add(pl.outerWay);
+                    }
+                }
+            }
+
+            result.add(pol);
+        }
+
+        return result;
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/gui/MainMenu.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/MainMenu.java	(revision 3703)
+++ /trunk/src/org/openstreetmap/josm/gui/MainMenu.java	(revision 3704)
@@ -25,4 +25,5 @@
 import org.openstreetmap.josm.actions.CopyAction;
 import org.openstreetmap.josm.actions.CreateCircleAction;
+import org.openstreetmap.josm.actions.CreateMultipolygonAction;
 import org.openstreetmap.josm.actions.DeleteAction;
 import org.openstreetmap.josm.actions.DistributeAction;
@@ -135,4 +136,6 @@
     /* View menu */
     public final JosmAction toggleGPXLines = new ToggleGPXLinesAction();
+    public final InfoAction info = new InfoAction();
+    public final HistoryInfoAction historyinfo = new HistoryInfoAction();
 
     /* Tools menu */
@@ -154,6 +157,5 @@
     public final JosmAction simplifyWay = new SimplifyWayAction();
     public final JosmAction joinAreas = new JoinAreasAction();
-    public final InfoAction info = new InfoAction();
-    public final HistoryInfoAction historyinfo = new HistoryInfoAction();
+    public final JosmAction createMultipolygon = new CreateMultipolygonAction();
 
     /* Audio menu */
@@ -319,5 +321,7 @@
         add(toolsMenu, joinNodeWay);
         add(toolsMenu, unglueNodes);
+        toolsMenu.addSeparator();
         add(toolsMenu, joinAreas);
+        add(toolsMenu, createMultipolygon);
 
         if (!Main.pref.getBoolean("audio.menuinvisible", false)) {
Index: /trunk/src/org/openstreetmap/josm/plugins/PluginHandler.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/plugins/PluginHandler.java	(revision 3703)
+++ /trunk/src/org/openstreetmap/josm/plugins/PluginHandler.java	(revision 3704)
@@ -89,5 +89,5 @@
             {"usertools", IN_CORE},
             {"AgPifoJ", IN_CORE}, {"utilsplugin", IN_CORE}, {"ghost", IN_CORE},
-            {"validator", IN_CORE}}) {
+            {"validator", IN_CORE}, {"multipoly", IN_CORE}}) {
             DEPRECATED_PLUGINS.put(depr[0], depr.length >= 2 ? depr[1] : null);
         }
