Index: trunk/images_nodist/downloadprimitive.svg
===================================================================
--- trunk/images_nodist/downloadprimitive.svg	(revision 2923)
+++ trunk/images_nodist/downloadprimitive.svg	(revision 2923)
@@ -0,0 +1,102 @@
+<?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:xlink="http://www.w3.org/1999/xlink"
+   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+   id="svg2440"
+   sodipodi:version="0.32"
+   inkscape:version="0.47 r22583"
+   width="24"
+   height="24"
+   version="1.0"
+   sodipodi:docname="downloadprimitive.svg"
+   inkscape:output_extension="org.inkscape.output.svg.inkscape"
+   inkscape:export-filename="C:\Documents and Settings\matthiasj\My Documents\Eclipse\core\images\downloadprimitive.png"
+   inkscape:export-xdpi="90"
+   inkscape:export-ydpi="90">
+  <metadata
+     id="metadata2445">
+    <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>
+  <defs
+     id="defs2443">
+    <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="perspective2447" />
+  </defs>
+  <sodipodi:namedview
+     inkscape:window-height="709"
+     inkscape:window-width="884"
+     inkscape:pageshadow="2"
+     inkscape:pageopacity="0.0"
+     guidetolerance="10.0"
+     gridtolerance="10.0"
+     objecttolerance="10.0"
+     borderopacity="1.0"
+     bordercolor="#666666"
+     pagecolor="#ffffff"
+     id="base"
+     showgrid="false"
+     inkscape:zoom="9.625"
+     inkscape:cx="8.1098883"
+     inkscape:cy="12.749824"
+     inkscape:window-x="181"
+     inkscape:window-y="114"
+     inkscape:current-layer="svg2440"
+     showguides="true"
+     inkscape:guide-bbox="true"
+     inkscape:window-maximized="0" />
+  <image
+     sodipodi:absref="C:\Documents and Settings\matthiasj\My Documents\Eclipse\core\images_nodist\..\images\download.png"
+     xlink:href="..\images\download.png"
+     y="4"
+     x="0"
+     height="24"
+     width="24"
+     id="image2449" />
+  <path
+     style="fill:none;stroke:#000000;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
+     d="m 3,9 11,-6 7,8"
+     id="path3604"
+     sodipodi:nodetypes="ccc" />
+  <rect
+     style="fill:#ffffff;stroke:#ff0000;stroke-width:0.99975336000000004;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;fill-opacity:1"
+     id="rect2824"
+     width="3.0002465"
+     height="3.0002465"
+     x="1.4993833"
+     y="7.50037" />
+  <rect
+     style="fill:#ffffff;stroke:#ff0000;stroke-width:1.00036620999999990;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;fill-opacity:1"
+     id="rect2826"
+     width="2.9996338"
+     height="2.9996338"
+     x="12.500183"
+     y="1.5001831" />
+  <rect
+     style="fill:#ffffff;stroke:#ff0000;stroke-width:0.99982095000000004;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none;fill-opacity:1"
+     id="rect2828"
+     width="3.0001793"
+     height="3.0001791"
+     x="19.499554"
+     y="9.500268" />
+</svg>
Index: trunk/src/org/openstreetmap/josm/actions/DownloadPrimitiveAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/DownloadPrimitiveAction.java	(revision 2923)
+++ trunk/src/org/openstreetmap/josm/actions/DownloadPrimitiveAction.java	(revision 2923)
@@ -0,0 +1,105 @@
+// License: GPL. See LICENSE file for details.
+package org.openstreetmap.josm.actions;
+
+import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.downloadtasks.DownloadPrimitiveTask;
+import org.openstreetmap.josm.actions.downloadtasks.DownloadReferrersTask;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
+import org.openstreetmap.josm.data.osm.SimplePrimitiveId;
+import org.openstreetmap.josm.gui.ExtendedDialog;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.gui.widgets.OsmIdTextField;
+import org.openstreetmap.josm.gui.widgets.OsmPrimitiveTypesComboBox;
+import org.openstreetmap.josm.tools.Shortcut;
+
+/**
+ * Download an OsmPrimitive by specifying type and ID
+ *
+ * @author Matthias Julius
+ */
+public class DownloadPrimitiveAction extends JosmAction {
+
+    public DownloadPrimitiveAction() {
+        super(tr("Download object..."), "downloadprimitive", tr("Download OSM object by ID."),
+                Shortcut.registerShortcut("system:download_primitive", tr("File: {0}", tr("Download Object...")), KeyEvent.VK_O, Shortcut.GROUP_MENU + Shortcut.GROUPS_ALT1), true);
+        putValue("help", ht("/Action/DownloadObject"));
+    }
+
+    public void actionPerformed(ActionEvent e) {
+        JCheckBox layer = new JCheckBox(tr("Separate Layer"));
+        layer.setToolTipText(tr("Select if the data should be downloaded into a new layer"));
+        layer.setSelected(Main.pref.getBoolean("download.newlayer"));
+        JCheckBox referrers = new JCheckBox(tr("Download referrers"));
+        referrers.setToolTipText(tr("Select if the referrers of the object should be downloaded as well"));
+        referrers.setSelected(Main.pref.getBoolean("downloadprimitive.referrers"));
+        JPanel all = new JPanel(new GridBagLayout());
+        GridBagConstraints gc = new GridBagConstraints();
+        gc.fill = GridBagConstraints.HORIZONTAL;
+        gc.anchor = GridBagConstraints.FIRST_LINE_START;
+        gc.gridy = 0;
+        gc.weightx = 0;
+        all.add(new JLabel(tr("Object type:")), gc);
+        OsmPrimitiveTypesComboBox cbType = new OsmPrimitiveTypesComboBox();
+        cbType.setToolTipText("Choose the OSM object type");
+        gc.weightx = 1;
+        all.add(cbType, gc);
+        gc.gridy = 1;
+        gc.weightx = 0;
+        all.add(new JLabel(tr("Object ID:")), gc);
+        OsmIdTextField tfId = new OsmIdTextField();
+        tfId.setToolTipText(tr("Enter the ID of the object that should be downloaded"));
+        gc.weightx = 1;
+        all.add(tfId, gc);
+        gc.gridy = 2;
+        gc.fill = GridBagConstraints.BOTH;
+        gc.weighty = 1.0;
+        gc.weightx = 0;
+        all.add(referrers, gc);
+        gc.gridy = 3;
+        all.add(layer, gc);
+        ExtendedDialog dialog = new ExtendedDialog(Main.parent,
+                tr("Download Object"),
+                new String[] {tr("Download object"), tr("Cancel")}
+        );
+        dialog.setContent(all, false);
+        dialog.setButtonIcons(new String[] {"download.png", "cancel.png"});
+        dialog.setToolTipTexts(new String[] {
+                tr("Start downloading"),
+                tr("Close dialog and cancel downloading")
+        });
+        dialog.configureContextsensitiveHelp("/Action/DownloadObject", true /* show help button */);
+        dialog.showDialog();
+        if (dialog.getValue() != 1) return;
+        Main.pref.put("downloadprimitive.referrers", referrers.isSelected());
+        Main.pref.put("download.newlayer", layer.isSelected());
+        download(layer.isSelected(), cbType.getType(), tfId.getOsmId(), referrers.isSelected());
+    }
+
+    /**
+     * Download the given primitive.
+     */
+    public void download(boolean newLayer, OsmPrimitiveType type, int id, boolean downloadReferrers) {
+        OsmDataLayer layer = getEditLayer();
+        if ((layer == null) || newLayer) {
+            layer = new OsmDataLayer(new DataSet(), OsmDataLayer.createNewName(), null);
+            Main.main.addLayer(layer);
+        }
+        Main.worker.submit(new DownloadPrimitiveTask(new SimplePrimitiveId(id, type), layer));
+        if (downloadReferrers) {
+            Main.worker.submit(new DownloadReferrersTask(layer, id, type));
+        }
+    }
+}
Index: trunk/src/org/openstreetmap/josm/actions/DownloadReferrersAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/DownloadReferrersAction.java	(revision 2922)
+++ trunk/src/org/openstreetmap/josm/actions/DownloadReferrersAction.java	(revision 2923)
@@ -4,32 +4,18 @@
 import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
 import static org.openstreetmap.josm.tools.I18n.tr;
-import static org.openstreetmap.josm.tools.I18n.trn;
 
 import java.awt.event.ActionEvent;
 import java.awt.event.KeyEvent;
-import java.io.IOException;
 import java.text.MessageFormat;
 import java.util.Collection;
-import java.util.HashMap;
 import java.util.Map;
-import java.util.Map.Entry;
-
-import javax.swing.JOptionPane;
-import javax.swing.SwingUtilities;
 
 import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.data.osm.DataSet;
-import org.openstreetmap.josm.data.osm.DataSetMerger;
+import org.openstreetmap.josm.actions.downloadtasks.DownloadReferrersTask;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
-import org.openstreetmap.josm.gui.PleaseWaitRunnable;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
-import org.openstreetmap.josm.gui.progress.ProgressMonitor;
-import org.openstreetmap.josm.io.OsmServerBackreferenceReader;
-import org.openstreetmap.josm.io.OsmTransferException;
 import org.openstreetmap.josm.tools.CheckParameterUtil;
-import org.openstreetmap.josm.tools.ExceptionUtil;
 import org.openstreetmap.josm.tools.Shortcut;
-import org.xml.sax.SAXException;
 
 /**
@@ -103,171 +89,4 @@
     }
 
-    /**
-     * The asynchronous task for downloading referring primitives
-     *
-     */
-    public static class DownloadReferrersTask extends PleaseWaitRunnable {
-        private boolean cancelled;
-        private Exception lastException;
-        private OsmServerBackreferenceReader reader;
-        /** the target layer */
-        private OsmDataLayer targetLayer;
-        /** the collection of child primitives */
-        private Map<Long, OsmPrimitiveType> children;
-        /** the parents */
-        private DataSet parents;
-
-        /**
-         * constructor
-         *
-         * @param targetLayer  the target layer for the downloaded primitives. Must not be null.
-         * @param children the collection of child primitives for which parents are to be downloaded
-         *
-         */
-        public DownloadReferrersTask(OsmDataLayer targetLayer, Collection<OsmPrimitive> children) {
-            super("Download referrers", false /* don't ignore exception*/);
-            CheckParameterUtil.ensureParameterNotNull(targetLayer, "targetLayer");
-            cancelled = false;
-            this.children = new HashMap<Long, OsmPrimitiveType>();
-            if (children != null) {
-                for (OsmPrimitive p: children) {
-                    if (! p.isNew()) {
-                        this.children.put(p.getId(), OsmPrimitiveType.from(p));
-                    }
-                }
-            }
-            this.targetLayer = targetLayer;
-            parents = new DataSet();
-        }
-
-        /**
-         * constructor
-         *
-         * @param targetLayer  the target layer for the downloaded primitives. Must not be null.
-         * @param primitives  the collection of children for which parents are to be downloaded. Children
-         * are specified by their id and  their type.
-         *
-         */
-        public DownloadReferrersTask(OsmDataLayer targetLayer, Map<Long, OsmPrimitiveType> children) {
-            super("Download referrers", false /* don't ignore exception*/);
-            CheckParameterUtil.ensureParameterNotNull(targetLayer, "targetLayer");
-            cancelled = false;
-            this.children = new HashMap<Long, OsmPrimitiveType>();
-            if (children != null) {
-                for (Entry<Long, OsmPrimitiveType> entry : children.entrySet()) {
-                    if (entry.getKey() > 0 && entry.getValue() != null) {
-                        children.put(entry.getKey(), entry.getValue());
-                    }
-                }
-            }
-            this.targetLayer = targetLayer;
-            parents = new DataSet();
-        }
-
-        /**
-         * constructor
-         *
-         * @param targetLayer  the target layer. Must not be null.
-         * @param id the primitive id. id > 0 required.
-         * @param type the primitive type. type != null required
-         * @exception IllegalArgumentException thrown if id <= 0
-         * @exception IllegalArgumentException thrown if type == null
-         * @exception IllegalArgumentException thrown if targetLayer == null
-         *
-         */
-        public DownloadReferrersTask(OsmDataLayer targetLayer, long id, OsmPrimitiveType type) throws IllegalArgumentException {
-            super("Download referrers", false /* don't ignore exception*/);
-            CheckParameterUtil.ensureParameterNotNull(targetLayer, "targetLayer");
-            if (id <= 0)
-                throw new IllegalArgumentException(MessageFormat.format("Id > 0 required, got {0}", id));
-            CheckParameterUtil.ensureParameterNotNull(type, "type");
-            cancelled = false;
-            this.children = new HashMap<Long, OsmPrimitiveType>();
-            this.children.put(id, type);
-            this.targetLayer = targetLayer;
-            parents = new DataSet();
-        }
-
-        @Override
-        protected void cancel() {
-            cancelled = true;
-            synchronized(this) {
-                if (reader != null) {
-                    reader.cancel();
-                }
-            }
-        }
-
-        @Override
-        protected void finish() {
-            if (cancelled)
-                return;
-            if (lastException != null) {
-                ExceptionUtil.explainException(lastException);
-                return;
-            }
-
-            DataSetMerger visitor = new DataSetMerger(targetLayer.data, parents);
-            visitor.merge();
-            SwingUtilities.invokeLater(
-                    new Runnable() {
-                        public void run() {
-                            targetLayer.fireDataChange();
-                            targetLayer.onPostDownloadFromServer();
-                            Main.map.mapView.repaint();
-                        }
-                    }
-            );
-            if (visitor.getConflicts().isEmpty())
-                return;
-            targetLayer.getConflicts().add(visitor.getConflicts());
-            JOptionPane.showMessageDialog(
-                    Main.parent,
-                    trn("There was {0} conflict during import.",
-                            "There were {0} conflicts during import.",
-                            visitor.getConflicts().size(),
-                            visitor.getConflicts().size()
-                    ),
-                    trn("Conflict during download", "Conflicts during download", visitor.getConflicts().size()),
-                    JOptionPane.WARNING_MESSAGE
-            );
-        }
-
-        protected void downloadParents(long id, OsmPrimitiveType type, ProgressMonitor progressMonitor) throws OsmTransferException{
-            reader = new OsmServerBackreferenceReader(id, type);
-            DataSet ds = reader.parseOsm(progressMonitor);
-            synchronized(this) { // avoid race condition in cancel()
-                reader = null;
-            }
-            DataSetMerger visitor = new DataSetMerger(parents, ds);
-            visitor.merge();
-        }
-
-        @Override
-        protected void realRun() throws SAXException, IOException, OsmTransferException {
-            try {
-                progressMonitor.setTicksCount(children.size());
-                int i=1;
-                for (Entry<Long, OsmPrimitiveType> entry: children.entrySet()) {
-                    if (cancelled)
-                        return;
-                    String msg = "";
-                    switch(entry.getValue()) {
-                    case NODE: msg = tr("({0}/{1}) Loading parents of node {2}", i+1,children.size(), entry.getKey()); break;
-                    case WAY: msg = tr("({0}/{1}) Loading parents of way {2}", i+1,children.size(), entry.getKey()); break;
-                    case RELATION: msg = tr("({0}/{1}) Loading parents of relation {2}", i+1,children.size(), entry.getKey()); break;
-                    }
-                    progressMonitor.subTask(msg);
-                    downloadParents(entry.getKey(), entry.getValue(), progressMonitor.createSubTaskMonitor(1, false));
-                    i++;
-                }
-            } catch(Exception e) {
-                if (cancelled)
-                    return;
-                lastException = e;
-            }
-        }
-    }
-
     @Override
     protected void updateEnabledState() {
Index: trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadPrimitiveTask.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadPrimitiveTask.java	(revision 2923)
+++ trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadPrimitiveTask.java	(revision 2923)
@@ -0,0 +1,105 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.actions.downloadtasks;
+
+import static org.openstreetmap.josm.tools.CheckParameterUtil.ensureParameterNotNull;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+
+import javax.swing.SwingUtilities;
+
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.PrimitiveId;
+import org.openstreetmap.josm.gui.ExceptionDialogUtil;
+import org.openstreetmap.josm.gui.PleaseWaitRunnable;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.io.OsmServerObjectReader;
+import org.openstreetmap.josm.io.OsmTransferException;
+import org.xml.sax.SAXException;
+
+/**
+ * The asynchronous task for updating a collection of objects using multi fetch.
+ *
+ */
+public class DownloadPrimitiveTask extends PleaseWaitRunnable {
+    private DataSet ds;
+    private boolean canceled;
+    private Exception lastException;
+    private PrimitiveId primitiveId;
+    private OsmDataLayer layer;
+    private OsmServerObjectReader reader;
+
+    /**
+     * Creates the  task
+     *
+     * @param layer the layer in which primitives are updated. Must not be null.
+     * @param toUpdate a collection of primitives to update from the server. Set to
+     * the empty collection if null.
+     * @throws IllegalArgumentException thrown if layer is null.
+     */
+    public DownloadPrimitiveTask(PrimitiveId id, OsmDataLayer layer) {
+        super(tr("Download object"), false /* don't ignore exception */);
+        ensureParameterNotNull(layer, "layer");
+        this.layer = layer;
+        this.primitiveId = id;
+    }
+
+    @Override
+    protected void cancel() {
+        canceled = true;
+        synchronized(this) {
+            if (reader != null) {
+                reader.cancel();
+            }
+        }
+    }
+
+    @Override
+    protected void finish() {
+        if (canceled)
+            return;
+        if (lastException != null) {
+            ExceptionDialogUtil.explainException(lastException);
+            return;
+        }
+        Runnable r = new Runnable() {
+            public void run() {
+                layer.mergeFrom(ds);
+                layer.onPostDownloadFromServer();
+            }
+        };
+
+        if (SwingUtilities.isEventDispatchThread()) {
+            r.run();
+        } else {
+            try {
+                SwingUtilities.invokeAndWait(r);
+            } catch(InterruptedException e) {
+                e.printStackTrace();
+            } catch(InvocationTargetException e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    @Override
+    protected void realRun() throws SAXException, IOException, OsmTransferException {
+        this.ds = new DataSet();
+        try {
+            synchronized(this) {
+                if (canceled) return;
+                reader = new OsmServerObjectReader(primitiveId, true);
+            }
+            ds = reader.parseOsm(progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
+            synchronized(this) {
+                reader = null;
+            }
+        } catch(Exception e) {
+            if (canceled)
+                return;
+            lastException = e;
+        }
+    }
+}
Index: trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadReferrersTask.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadReferrersTask.java	(revision 2923)
+++ trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadReferrersTask.java	(revision 2923)
@@ -0,0 +1,218 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.actions.downloadtasks;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+import static org.openstreetmap.josm.tools.I18n.trn;
+
+import java.io.IOException;
+import java.text.MessageFormat;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Map.Entry;
+
+import javax.swing.JOptionPane;
+import javax.swing.SwingUtilities;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.DataSetMerger;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
+import org.openstreetmap.josm.data.osm.PrimitiveId;
+import org.openstreetmap.josm.gui.PleaseWaitRunnable;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.io.OsmServerBackreferenceReader;
+import org.openstreetmap.josm.io.OsmTransferException;
+import org.openstreetmap.josm.tools.CheckParameterUtil;
+import org.openstreetmap.josm.tools.ExceptionUtil;
+import org.xml.sax.SAXException;
+
+/**
+ * The asynchronous task for downloading referring primitives
+ *
+ */
+public class DownloadReferrersTask extends PleaseWaitRunnable {
+    private boolean cancelled;
+    private Exception lastException;
+    private OsmServerBackreferenceReader reader;
+    /** the target layer */
+    private OsmDataLayer targetLayer;
+    /** the collection of child primitives */
+    private Map<Long, OsmPrimitiveType> children;
+    /** the parents */
+    private DataSet parents;
+
+    /**
+     * constructor
+     *
+     * @param targetLayer  the target layer for the downloaded primitives. Must not be null.
+     * @param children the collection of child primitives for which parents are to be downloaded
+     *
+     */
+    public DownloadReferrersTask(OsmDataLayer targetLayer, Collection<OsmPrimitive> children) {
+        super("Download referrers", false /* don't ignore exception*/);
+        CheckParameterUtil.ensureParameterNotNull(targetLayer, "targetLayer");
+        cancelled = false;
+        this.children = new HashMap<Long, OsmPrimitiveType>();
+        if (children != null) {
+            for (OsmPrimitive p: children) {
+                if (! p.isNew()) {
+                    this.children.put(p.getId(), OsmPrimitiveType.from(p));
+                }
+            }
+        }
+        this.targetLayer = targetLayer;
+        parents = new DataSet();
+    }
+
+    /**
+     * constructor
+     *
+     * @param targetLayer  the target layer for the downloaded primitives. Must not be null.
+     * @param primitives  the collection of children for which parents are to be downloaded. Children
+     * are specified by their id and  their type.
+     *
+     */
+    public DownloadReferrersTask(OsmDataLayer targetLayer, Map<Long, OsmPrimitiveType> children) {
+        super("Download referrers", false /* don't ignore exception*/);
+        CheckParameterUtil.ensureParameterNotNull(targetLayer, "targetLayer");
+        cancelled = false;
+        this.children = new HashMap<Long, OsmPrimitiveType>();
+        if (children != null) {
+            for (Entry<Long, OsmPrimitiveType> entry : children.entrySet()) {
+                if (entry.getKey() > 0 && entry.getValue() != null) {
+                    children.put(entry.getKey(), entry.getValue());
+                }
+            }
+        }
+        this.targetLayer = targetLayer;
+        parents = new DataSet();
+    }
+
+    /**
+     * constructor
+     *
+     * @param targetLayer  the target layer. Must not be null.
+     * @param id the primitive id. id > 0 required.
+     * @param type the primitive type. type != null required
+     * @exception IllegalArgumentException thrown if id <= 0
+     * @exception IllegalArgumentException thrown if type == null
+     * @exception IllegalArgumentException thrown if targetLayer == null
+     *
+     */
+    public DownloadReferrersTask(OsmDataLayer targetLayer, long id, OsmPrimitiveType type) throws IllegalArgumentException {
+        super("Download referrers", false /* don't ignore exception*/);
+        CheckParameterUtil.ensureParameterNotNull(targetLayer, "targetLayer");
+        if (id <= 0)
+            throw new IllegalArgumentException(MessageFormat.format("Id > 0 required, got {0}", id));
+        CheckParameterUtil.ensureParameterNotNull(type, "type");
+        cancelled = false;
+        this.children = new HashMap<Long, OsmPrimitiveType>();
+        this.children.put(id, type);
+        this.targetLayer = targetLayer;
+        parents = new DataSet();
+    }
+
+    /**
+     * constructor
+     *
+     * @param targetLayer  the target layer. Must not be null.
+     * @param primitiveId a PrimitiveId object.
+     * @exception IllegalArgumentException thrown if id <= 0
+     * @exception IllegalArgumentException thrown if targetLayer == null
+     *
+     */
+    public DownloadReferrersTask(OsmDataLayer targetLayer, PrimitiveId primitiveId) throws IllegalArgumentException {
+        super("Download referrers", false /* don't ignore exception*/);
+        CheckParameterUtil.ensureParameterNotNull(targetLayer, "targetLayer");
+        if (primitiveId.isNew())
+            throw new IllegalArgumentException(MessageFormat.format("Cannot download referrers for new primitives (ID {0})", primitiveId.getUniqueId()));
+        cancelled = false;
+        this.children = new HashMap<Long, OsmPrimitiveType>();
+        this.children.put(primitiveId.getUniqueId(), primitiveId.getType());
+        this.targetLayer = targetLayer;
+        parents = new DataSet();
+    }
+
+    @Override
+    protected void cancel() {
+        cancelled = true;
+        synchronized(this) {
+            if (reader != null) {
+                reader.cancel();
+            }
+        }
+    }
+
+    @Override
+    protected void finish() {
+        if (cancelled)
+            return;
+        if (lastException != null) {
+            ExceptionUtil.explainException(lastException);
+            return;
+        }
+
+        DataSetMerger visitor = new DataSetMerger(targetLayer.data, parents);
+        visitor.merge();
+        SwingUtilities.invokeLater(
+                new Runnable() {
+                    public void run() {
+                        targetLayer.fireDataChange();
+                        targetLayer.onPostDownloadFromServer();
+                        Main.map.mapView.repaint();
+                    }
+                }
+        );
+        if (visitor.getConflicts().isEmpty())
+            return;
+        targetLayer.getConflicts().add(visitor.getConflicts());
+        JOptionPane.showMessageDialog(
+                Main.parent,
+                trn("There was {0} conflict during import.",
+                        "There were {0} conflicts during import.",
+                        visitor.getConflicts().size(),
+                        visitor.getConflicts().size()
+                ),
+                trn("Conflict during download", "Conflicts during download", visitor.getConflicts().size()),
+                JOptionPane.WARNING_MESSAGE
+        );
+    }
+
+    protected void downloadParents(long id, OsmPrimitiveType type, ProgressMonitor progressMonitor) throws OsmTransferException{
+        reader = new OsmServerBackreferenceReader(id, type);
+        DataSet ds = reader.parseOsm(progressMonitor);
+        synchronized(this) { // avoid race condition in cancel()
+            reader = null;
+        }
+        DataSetMerger visitor = new DataSetMerger(parents, ds);
+        visitor.merge();
+    }
+
+    @Override
+    protected void realRun() throws SAXException, IOException, OsmTransferException {
+        try {
+            progressMonitor.setTicksCount(children.size());
+            int i=1;
+            for (Entry<Long, OsmPrimitiveType> entry: children.entrySet()) {
+                if (cancelled)
+                    return;
+                String msg = "";
+                switch(entry.getValue()) {
+                case NODE: msg = tr("({0}/{1}) Loading parents of node {2}", i+1,children.size(), entry.getKey()); break;
+                case WAY: msg = tr("({0}/{1}) Loading parents of way {2}", i+1,children.size(), entry.getKey()); break;
+                case RELATION: msg = tr("({0}/{1}) Loading parents of relation {2}", i+1,children.size(), entry.getKey()); break;
+                }
+                progressMonitor.subTask(msg);
+                downloadParents(entry.getKey(), entry.getValue(), progressMonitor.createSubTaskMonitor(1, false));
+                i++;
+            }
+        } catch(Exception e) {
+            if (cancelled)
+                return;
+            lastException = e;
+        }
+    }
+}
Index: trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitiveType.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitiveType.java	(revision 2922)
+++ trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitiveType.java	(revision 2923)
@@ -1,4 +1,5 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.data.osm;
+import static org.openstreetmap.josm.tools.I18n.marktr;
 import static org.openstreetmap.josm.tools.I18n.tr;
 
@@ -7,7 +8,7 @@
 public enum OsmPrimitiveType {
 
-    NODE ("node", Node.class, NodeData.class),
-    WAY  ("way", Way.class, WayData.class),
-    RELATION ("relation", Relation.class, RelationData.class);
+    NODE (marktr("node"), Node.class, NodeData.class),
+    WAY  (marktr("way"), Way.class, WayData.class),
+    RELATION (marktr("relation"), Relation.class, RelationData.class);
 
     private final String apiTypeName;
@@ -71,3 +72,7 @@
     }
 
+    @Override
+    public String toString() {
+        return tr(getAPIName());
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/MainMenu.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MainMenu.java	(revision 2922)
+++ trunk/src/org/openstreetmap/josm/gui/MainMenu.java	(revision 2923)
@@ -29,4 +29,5 @@
 import org.openstreetmap.josm.actions.DistributeAction;
 import org.openstreetmap.josm.actions.DownloadAction;
+import org.openstreetmap.josm.actions.DownloadPrimitiveAction;
 import org.openstreetmap.josm.actions.DownloadReferrersAction;
 import org.openstreetmap.josm.actions.DuplicateAction;
@@ -100,4 +101,5 @@
     public final JosmAction gpxExport = new GpxExportAction();
     public final DownloadAction download = new DownloadAction();
+    public final DownloadPrimitiveAction downloadPrimitive = new DownloadPrimitiveAction();
     public final DownloadReferrersAction downloadReferrers = new DownloadReferrersAction();
     public final CloseChangesetAction closeChangesetAction = new CloseChangesetAction();
@@ -210,4 +212,5 @@
         fileMenu.addSeparator();
         add(fileMenu, download);
+        add(fileMenu, downloadPrimitive);
         add(fileMenu, downloadReferrers);
         add(fileMenu, update);
Index: trunk/src/org/openstreetmap/josm/gui/widgets/OsmIdTextField.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/widgets/OsmIdTextField.java	(revision 2923)
+++ trunk/src/org/openstreetmap/josm/gui/widgets/OsmIdTextField.java	(revision 2923)
@@ -0,0 +1,64 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.widgets;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import javax.swing.JTextField;
+import javax.swing.text.JTextComponent;
+
+/**
+ * @author Matthias Julius
+ */
+public class OsmIdTextField extends JTextField {
+
+    private OsmIdValidator validator;
+
+    public OsmIdTextField() {
+        validator = OsmIdValidator.decorate(this);
+    }
+
+    public int getOsmId() {
+        return validator.getOsmId();
+    }
+
+    /**
+     * Validator for a changeset ID entered in a {@see JTextComponent}.
+     *
+     */
+    static private class OsmIdValidator extends AbstractTextComponentValidator {
+
+        static public OsmIdValidator decorate(JTextComponent tc) {
+            return new OsmIdValidator(tc);
+        }
+
+        public OsmIdValidator(JTextComponent tc) {
+            super(tc);
+        }
+
+        @Override
+        public boolean isValid() {
+            return getOsmId() > 0;
+        }
+
+        @Override
+        public void validate() {
+            if (!isValid()) {
+                feedbackInvalid(tr("The current value is not a valid OSM ID. Please enter an integer value > 0"));
+            } else {
+                feedbackValid(tr("Please enter an integer value > 0"));
+            }
+        }
+
+        public int getOsmId() {
+            String value  = getComponent().getText();
+            if (value == null || value.trim().length() == 0) return 0;
+            try {
+                int osmId = Integer.parseInt(value.trim());
+                if (osmId > 0) return osmId;
+                return 0;
+            } catch(NumberFormatException e) {
+                return 0;
+            }
+        }
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/widgets/OsmPrimitiveTypesComboBox.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/widgets/OsmPrimitiveTypesComboBox.java	(revision 2923)
+++ trunk/src/org/openstreetmap/josm/gui/widgets/OsmPrimitiveTypesComboBox.java	(revision 2923)
@@ -0,0 +1,22 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.widgets;
+
+import javax.swing.JComboBox;
+
+import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
+
+/**
+ * @author Matthias Julius
+ */
+public class OsmPrimitiveTypesComboBox extends JComboBox {
+
+    public OsmPrimitiveTypesComboBox() {
+        for (OsmPrimitiveType type: OsmPrimitiveType.values()){
+            addItem(type);
+        }
+    }
+
+    public OsmPrimitiveType getType() {
+        return (OsmPrimitiveType)this.getSelectedItem();
+    }
+}
