Index: src/org/openstreetmap/josm/actions/DownloadPrimitiveAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/DownloadPrimitiveAction.java	(revision 4070)
+++ src/org/openstreetmap/josm/actions/DownloadPrimitiveAction.java	(working copy)
@@ -8,6 +8,8 @@
 import java.awt.GridBagLayout;
 import java.awt.event.ActionEvent;
 import java.awt.event.KeyEvent;
+import java.util.List;
+import javax.swing.ComboBoxModel;
 
 import javax.swing.JCheckBox;
 import javax.swing.JLabel;
@@ -19,12 +21,16 @@
 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.Node;
 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.io.DownloadPrimitivesTask;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.gui.widgets.HtmlPanel;
 import org.openstreetmap.josm.gui.widgets.OsmIdTextField;
 import org.openstreetmap.josm.gui.widgets.OsmPrimitiveTypesComboBox;
+import org.openstreetmap.josm.io.MultiFetchServerObjectReader;
 import org.openstreetmap.josm.tools.Shortcut;
 
 /**
@@ -51,28 +57,31 @@
         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);
+        gc.gridy = 0;   gc.gridwidth=0;   gc.weightx = 0;
+        all.add(new HtmlPanel(tr("Please choose defalt primitive type and enter primitives numbers<br/>"
+                + " Examples: <b><ul><li>1 2 5</li><li>1, 2, 5</li><li>123,v2 123,v1</li></ul><br/></b>"
+                + " It is also possible to specify primitive types in the list: <b>w123, n110, w12, r15</b><br/>"
+                + " v-words are ignored for copy-paste from openstreetmap.org<br/><br/>")), gc);
+        gc.gridwidth=1;  gc.weightx = 0;  gc.gridy = 1; gc.gridx = 0;
+        all.add(new JLabel(tr("Object type:")),gc);
         OsmPrimitiveTypesComboBox cbType = new OsmPrimitiveTypesComboBox();
+        cbType.addItem(new SimpleListItem("auto", tr("Auto")));
         cbType.setToolTipText(tr("Choose the OSM object type"));
-        gc.weightx = 1;
+        gc.weightx = 1; gc.gridx = 1;
         all.add(cbType, gc);
-        gc.gridy = 1;
-        gc.weightx = 0;
+        gc.gridy = 2; gc.gridx = 0;   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"));
         // forward the enter key stroke to the download button
         tfId.getKeymap().removeKeyStrokeBinding(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, false));
-        gc.weightx = 1;
+        gc.gridx = 1;    gc.weightx = 1;
         all.add(tfId, gc);
-        gc.gridy = 2;
+        gc.gridy = 3;    gc.gridx = 0;
         gc.fill = GridBagConstraints.BOTH;
-        gc.weighty = 1.0;
-        gc.weightx = 0;
+        gc.weighty = 1.0;  gc.weightx = 0;
         all.add(referrers, gc);
-        gc.gridy = 3;
+        gc.gridy = 4;
         all.add(layer, gc);
         ExtendedDialog dialog = new ExtendedDialog(Main.parent,
                 tr("Download object"),
@@ -92,30 +101,45 @@
         Main.pref.putInteger("downloadprimitive.lasttype", cbType.getSelectedIndex());
         Main.pref.put("downloadprimitive.referrers", referrers.isSelected());
         Main.pref.put("download.newlayer", layer.isSelected());
-        int id = tfId.getOsmId();
-        if(id <= 0)
+
+        tfId.setType(cbType.getType());
+        if(tfId.readOsmIds()==false) {
             JOptionPane.showMessageDialog(
                     Main.parent,
-                    tr("Invalid ID specified. Cannot download object."),
+                    tr("Invalid ID list specified\n"
+                    + " Cannot download object."),
                     tr("Information"),
                     JOptionPane.INFORMATION_MESSAGE
             );
-        else
-            download(layer.isSelected(), cbType.getType(), id, referrers.isSelected());
+            return;
+        }
+
+        processItems(layer.isSelected(), cbType.getType(),tfId.getNodeIds(),
+             tfId.getWayIds(), tfId.getRelIds(), referrers.isSelected());
     }
-
-    /**
-     * Download the given primitive.
-     */
-    public void download(boolean newLayer, OsmPrimitiveType type, int id, boolean downloadReferrers) {
+    
+    void processItems(boolean newLayer, OsmPrimitiveType type, 
+            List<Long> nodeIds,List<Long> wayIds,List<Long> relIds,
+            boolean downloadReferrers) {
+        System.out.println(nodeIds);
+        System.out.println(wayIds);
+        System.out.println(relIds);
         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));
-        }
+            if ((layer == null) || newLayer) {
+                layer = new OsmDataLayer(new DataSet(), OsmDataLayer.createNewName(), null);
+                Main.main.addLayer(layer);
+            }     
+       Main.worker.submit(new DownloadPrimitivesTask(layer, nodeIds, wayIds, relIds,downloadReferrers));
     }
+
+    private void processMixedItems(boolean selected, OsmPrimitiveType osmPrimitiveType, int[] type, boolean osmIds) {
+        throw new UnsupportedOperationException("Not yet implemented");
+    }
+    
+    private static class SimpleListItem  {
+     final String data;
+     final String text;
+     public SimpleListItem(String data, String text) {  this.data = data;   this.text = text; }
+     @Override public String toString() { return text; }
+   }
 }
Index: src/org/openstreetmap/josm/gui/widgets/OsmIdTextField.java
===================================================================
--- src/org/openstreetmap/josm/gui/widgets/OsmIdTextField.java	(revision 4070)
+++ src/org/openstreetmap/josm/gui/widgets/OsmIdTextField.java	(working copy)
@@ -1,10 +1,15 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.gui.widgets;
 
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.StringTokenizer;
 import static org.openstreetmap.josm.tools.I18n.tr;
 
 import javax.swing.JTextField;
 import javax.swing.text.JTextComponent;
+import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
 
 /**
  * @author Matthias Julius
@@ -17,11 +22,36 @@
         validator = OsmIdValidator.decorate(this);
     }
 
-    public int getOsmId() {
+    public void setType(OsmPrimitiveType type) {
+        validator.type = type;
+    }
+
+    public long getOsmId() {
         return validator.getOsmId();
     }
 
     /**
+     * Get entered ID list - supports "1,2,3" "1 2   ,3" or even "1 2 3 v2 6 v8"
+     * @return array of id's
+     */
+    public List<Long> getNodeIds() {
+        return validator.nodeIds;
+    }
+
+    public List<Long> getWayIds() {
+        return validator.wayIds;
+    }
+
+    public List<Long> getRelIds() {
+        return validator.relIds;
+    }
+
+    public boolean readOsmIds() {
+        return validator.readOsmIds();
+    }
+
+
+    /**
      * Validator for a changeset ID entered in a {@see JTextComponent}.
      *
      */
@@ -31,13 +61,18 @@
             return new OsmIdValidator(tc);
         }
 
+        private List<Long> nodeIds=new ArrayList<Long>();
+        private List<Long> wayIds=new ArrayList<Long>();
+        private List<Long> relIds=new ArrayList<Long>();
+        private OsmPrimitiveType type;
+
         public OsmIdValidator(JTextComponent tc) {
             super(tc, false);
         }
 
         @Override
         public boolean isValid() {
-            return getOsmId() > 0;
+            return getOsmId() > 0 || readOsmIds()!=false;
         }
 
         @Override
@@ -49,16 +84,42 @@
             }
         }
 
-        public int getOsmId() {
+        public long getOsmId() {
             String value  = getComponent().getText();
             if (value == null || value.trim().length() == 0) return 0;
             try {
-                int osmId = Integer.parseInt(value.trim());
+                long osmId = Long.parseLong(value.trim());
                 if (osmId > 0) return osmId;
                 return 0;
             } catch(NumberFormatException e) {
                 return 0;
             }
         }
+        public boolean readOsmIds() {
+            String value  = getComponent().getText();
+            char c;
+            if (value == null || value.trim().length() == 0) return false;
+            try {
+                nodeIds.clear(); wayIds.clear(); relIds.clear();
+                //String[] parts = value.split("[,\\.\\s\\t\\n]+");
+                StringTokenizer st = new StringTokenizer(value,",.+/ \t\n");
+                String s;
+                while (st.hasMoreTokens()) {
+                    s = st.nextToken();
+                    // convert tokens to int skipping v-words (version v2 etc)
+                    c = s.charAt(0);
+                    if (c=='v') continue;
+                    if (c=='n') nodeIds.add(Long.parseLong(s.substring(1))); else
+                    if (c=='w') wayIds.add(Long.parseLong(s.substring(1))); else
+                    if (c=='r') relIds.add(Long.parseLong(s.substring(1))); else
+                    if (type==OsmPrimitiveType.NODE) nodeIds.add(Long.parseLong(s)); else
+                    if (type==OsmPrimitiveType.WAY) wayIds.add(Long.parseLong(s)); else
+                    if (type==OsmPrimitiveType.RELATION) relIds.add(Long.parseLong(s));
+                    }
+                return true;
+            } catch(NumberFormatException e) {
+                return false;
+            }
+        }
     }
 }
Index: src/org/openstreetmap/josm/gui/widgets/OsmPrimitiveTypesComboBox.java
===================================================================
--- src/org/openstreetmap/josm/gui/widgets/OsmPrimitiveTypesComboBox.java	(revision 4070)
+++ src/org/openstreetmap/josm/gui/widgets/OsmPrimitiveTypesComboBox.java	(working copy)
@@ -18,6 +18,10 @@
     }
 
     public OsmPrimitiveType getType() {
-        return (OsmPrimitiveType)this.getSelectedItem();
+        try {
+            return (OsmPrimitiveType)this.getSelectedItem();
+        } catch (Exception e) {
+            return null;
+        }
     }
 }
Index: src/org/openstreetmap/josm/gui/io/DownloadPrimitivesTask.java
===================================================================
--- src/org/openstreetmap/josm/gui/io/DownloadPrimitivesTask.java	(revision 0)
+++ src/org/openstreetmap/josm/gui/io/DownloadPrimitivesTask.java	(revision 0)
@@ -0,0 +1,180 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.io;
+
+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 java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.logging.Logger;
+
+import javax.swing.SwingUtilities;
+
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.DataSetMerger;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.Way;
+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.MultiFetchServerObjectReader;
+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 DownloadPrimitivesTask extends PleaseWaitRunnable {
+    @SuppressWarnings("unused")
+    static private final Logger logger = Logger.getLogger(UpdatePrimitivesTask.class.getName());
+
+    private DataSet ds;
+    private boolean canceled;
+    private Exception lastException;
+    private List<Long> nodeIds;
+    private List<Long> wayIds;
+    private List<Long> relIds;
+
+    private OsmDataLayer layer;
+    private MultiFetchServerObjectReader multiObjectReader;
+    private OsmServerObjectReader objectReader;
+    private final boolean downloadReferrers;
+
+    /**
+     * 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 DownloadPrimitivesTask(OsmDataLayer layer, List<Long>  nodeIds,
+            List<Long>  wayIds,List<Long>  relIds, boolean downloadReferrers) throws IllegalArgumentException{
+        super(tr("Download objects"), false /* don't ignore exception */);
+        ensureParameterNotNull(layer, "layer");
+        this.nodeIds = nodeIds; this.wayIds = wayIds;  this.relIds = relIds;
+        this.layer = layer;
+        this.downloadReferrers = downloadReferrers;
+    }
+
+    @Override
+    protected void cancel() {
+        canceled = true;
+        synchronized(this) {
+            if (multiObjectReader != null) {
+                multiObjectReader.cancel();
+            }
+            if (objectReader != null) {
+                objectReader.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();
+            }
+        }
+    }
+
+    protected void initMultiFetchReaderWithNodes(MultiFetchServerObjectReader reader) {
+        getProgressMonitor().indeterminateSubTask(tr("Initializing nodes to download ..."));
+        for (Long id : nodeIds) {
+            Node n=(Node) layer.data.getPrimitiveById(id, OsmPrimitiveType.NODE);
+            if (n == null) n=new Node(id);
+            reader.append(n);
+        }
+    }
+
+    protected void initMultiFetchReaderWithWays(MultiFetchServerObjectReader reader) {
+        getProgressMonitor().indeterminateSubTask(tr("Initializing ways to download ..."));
+        for (Long id : wayIds) {
+            Way w=(Way) layer.data.getPrimitiveById(id, OsmPrimitiveType.WAY);
+            if (w == null) w=new Way(id);
+            reader.append(w);
+        }
+    }
+
+    protected void initMultiFetchReaderWithRelations(MultiFetchServerObjectReader reader) {
+        getProgressMonitor().indeterminateSubTask(tr("Initializing relations to download ..."));
+        for (Long id : relIds) {
+            Relation r=(Relation) layer.data.getPrimitiveById(id, OsmPrimitiveType.RELATION);
+            if (r == null) r=new Relation(id);
+            reader.append(r);
+        }
+    }
+
+    @Override
+    protected void realRun() throws SAXException, IOException, OsmTransferException {
+        this.ds = new DataSet();
+        DataSet theirDataSet;
+        try {
+            synchronized(this) {
+                if (canceled) return;
+                multiObjectReader = new MultiFetchServerObjectReader();
+            }
+            initMultiFetchReaderWithNodes(multiObjectReader);
+            initMultiFetchReaderWithWays(multiObjectReader);
+            initMultiFetchReaderWithRelations(multiObjectReader);
+            theirDataSet = multiObjectReader.parseOsm(progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
+            synchronized(this) {
+                multiObjectReader = null;
+            }
+            DataSetMerger merger = new DataSetMerger(ds, theirDataSet);
+            merger.merge();
+            // a way loaded with MultiFetch may have incomplete nodes because at least one of its
+            // nodes isn't present in the local data set. We therefore fully load all
+            // ways with incomplete nodes.
+            //
+            for (Way w : ds.getWays()) {
+                if (canceled) return;
+                if (w.hasIncompleteNodes()) {
+                    synchronized(this) {
+                        if (canceled) return;
+                        objectReader = new OsmServerObjectReader(w.getId(), OsmPrimitiveType.WAY, true /* full */);
+                    }
+                    theirDataSet = objectReader.parseOsm(progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
+                    synchronized (this) {
+                        objectReader = null;
+                    }
+                    merger = new DataSetMerger(ds, theirDataSet);
+                    merger.merge();
+                }
+            }
+        } catch(Exception e) {
+            if (canceled)
+                return;
+            lastException = e;
+        }
+    }
+}
