Index: trunk/src/org/openstreetmap/josm/actions/OpenLocationAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/OpenLocationAction.java	(revision 4529)
+++ trunk/src/org/openstreetmap/josm/actions/OpenLocationAction.java	(revision 4530)
@@ -23,4 +23,5 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.actions.downloadtasks.DownloadGpsTask;
+import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmChangeTask;
 import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask;
 import org.openstreetmap.josm.actions.downloadtasks.DownloadTask;
@@ -51,4 +52,5 @@
         addDownloadTaskClass(DownloadOsmTask.class);
         addDownloadTaskClass(DownloadGpsTask.class);
+        addDownloadTaskClass(DownloadOsmChangeTask.class);
     }
 
Index: trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmChangeTask.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmChangeTask.java	(revision 4530)
+++ trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmChangeTask.java	(revision 4530)
@@ -0,0 +1,70 @@
+package org.openstreetmap.josm.actions.downloadtasks;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.concurrent.Future;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.gui.io.UpdatePrimitivesTask;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+import org.openstreetmap.josm.io.OsmServerLocationReader;
+import org.openstreetmap.josm.io.OsmServerReader;
+import org.openstreetmap.josm.io.OsmTransferException;
+
+public class DownloadOsmChangeTask extends DownloadOsmTask {
+
+    @Override
+    public boolean acceptsUrl(String url) {
+        return url != null && url.matches("http://.*/api/0.6/changeset/\\p{Digit}+/download");
+    }
+
+    /* (non-Javadoc)
+     * @see org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask#download(boolean, org.openstreetmap.josm.data.Bounds, org.openstreetmap.josm.gui.progress.ProgressMonitor)
+     */
+    @Override
+    public Future<?> download(boolean newLayer, Bounds downloadArea,
+            ProgressMonitor progressMonitor) {
+        return null;
+    }
+
+    /* (non-Javadoc)
+     * @see org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask#loadUrl(boolean, java.lang.String, org.openstreetmap.josm.gui.progress.ProgressMonitor)
+     */
+    @Override
+    public Future<?> loadUrl(boolean new_layer, String url,
+            ProgressMonitor progressMonitor) {
+        downloadTask = new DownloadTask(new_layer,
+                new OsmServerLocationReader(url),
+                progressMonitor);
+        return Main.worker.submit(downloadTask);
+    }
+    
+    protected class DownloadTask extends DownloadOsmTask.DownloadTask {
+
+        public DownloadTask(boolean newLayer, OsmServerReader reader,
+                ProgressMonitor progressMonitor) {
+            super(newLayer, reader, progressMonitor);
+        }
+
+        /* (non-Javadoc)
+         * @see org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask.DownloadTask#parseDataSet()
+         */
+        @Override
+        protected DataSet parseDataSet() throws OsmTransferException {
+            return reader.parseOsmChange(progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
+        }
+
+        /* (non-Javadoc)
+         * @see org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask.DownloadTask#finish()
+         */
+        @Override
+        protected void finish() {
+            super.finish();
+            progressMonitor.subTask(tr("Updating data"));
+            UpdatePrimitivesTask task = new UpdatePrimitivesTask(targetLayer, downloadedData.allPrimitives());
+            Main.worker.submit(task);
+        }
+    }
+}
Index: trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTask.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTask.java	(revision 4529)
+++ trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmTask.java	(revision 4530)
@@ -33,4 +33,6 @@
     protected DataSet downloadedData;
     protected DownloadTask downloadTask;
+    
+    protected OsmDataLayer targetLayer;
 
     protected void rememberDownloadedData(DataSet ds) {
@@ -79,5 +81,5 @@
     }
 
-     protected  class DownloadTask extends PleaseWaitRunnable {
+    protected class DownloadTask extends PleaseWaitRunnable {
         protected OsmServerReader reader;
         protected DataSet dataSet;
@@ -89,4 +91,8 @@
             this.newLayer = newLayer;
         }
+        
+        protected DataSet parseDataSet() throws OsmTransferException {
+            return reader.parseOsm(progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
+        }
 
         @Override public void realRun() throws IOException, SAXException, OsmTransferException {
@@ -94,5 +100,5 @@
                 if (isCanceled())
                     return;
-                dataSet = reader.parseOsm(progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
+                dataSet = parseDataSet();
             } catch(Exception e) {
                 if (isCanceled()) {
@@ -161,36 +167,33 @@
                 // or it is not clear which layer to merge to
                 //
-                OsmDataLayer layer = createNewLayer();
+                targetLayer = createNewLayer();
                 final boolean isDisplayingMapView = Main.isDisplayingMapView();
 
-                Main.main.addLayer(layer);
+                Main.main.addLayer(targetLayer);
 
                 // If the mapView is not there yet, we cannot calculate the bounds (see constructor of MapView).
                 // Otherwise jump to the current download.
                 if (isDisplayingMapView) {
-                    BoundingXYVisitor v = new BoundingXYVisitor();
-                    if (currentBounds != null) {
-                        v.visit(currentBounds);
-                    } else {
-                        v.computeBoundingBox(dataSet.getNodes());
-                    }
-                    Main.map.mapView.recalculateCenterScale(v);
+                    computeBboxAndCenterScale();
                 }
             } else {
-                OsmDataLayer target;
-                target = getEditLayer();
-                if (target == null) {
-                    target = getFirstDataLayer();
-                }
-                target.mergeFrom(dataSet);
-                BoundingXYVisitor v = new BoundingXYVisitor();
-                if (currentBounds != null) {
-                    v.visit(currentBounds);
-                } else {
-                    v.computeBoundingBox(dataSet.getNodes());
-                }
-                Main.map.mapView.recalculateCenterScale(v);
-                target.onPostDownloadFromServer();
-            }
+                targetLayer = getEditLayer();
+                if (targetLayer == null) {
+                    targetLayer = getFirstDataLayer();
+                }
+                targetLayer.mergeFrom(dataSet);
+                computeBboxAndCenterScale();
+                targetLayer.onPostDownloadFromServer();
+            }
+        }
+        
+        protected void computeBboxAndCenterScale() {
+            BoundingXYVisitor v = new BoundingXYVisitor();
+            if (currentBounds != null) {
+                v.visit(currentBounds);
+            } else {
+                v.computeBoundingBox(dataSet.getNodes());
+            }
+            Main.map.mapView.recalculateCenterScale(v);
         }
 
Index: trunk/src/org/openstreetmap/josm/io/OsmChangeReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmChangeReader.java	(revision 4530)
+++ trunk/src/org/openstreetmap/josm/io/OsmChangeReader.java	(revision 4530)
@@ -0,0 +1,111 @@
+package org.openstreetmap.josm.io;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.io.InputStream;
+
+import javax.xml.stream.XMLStreamConstants;
+import javax.xml.stream.XMLStreamException;
+
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.gui.progress.ProgressMonitor;
+
+public class OsmChangeReader extends OsmReader {
+
+    /**
+     * constructor (for private and subclasses use only)
+     *
+     * @see #parseDataSet(InputStream, DataSet, ProgressMonitor)
+     */
+    protected OsmChangeReader() {
+    }
+    
+    /* (non-Javadoc)
+     * @see org.openstreetmap.josm.io.OsmReader#parseRoot()
+     */
+    @Override
+    protected void parseRoot() throws XMLStreamException {
+        if (parser.getLocalName().equals("osmChange")) {
+            parseOsmChange();
+        } else {
+            parseUnknown();
+        }
+    }
+
+    private void parseOsmChange() throws XMLStreamException {
+        String v = parser.getAttributeValue(null, "version");
+        if (v == null) {
+            throwException(tr("Missing mandatory attribute ''{0}''.", "version"));
+        }
+        if (!v.equals("0.6")) {
+            throwException(tr("Unsupported version: {0}", v));
+        }
+        ds.setVersion(v);
+        while (parser.hasNext()) {
+            int event = parser.next();
+            if (event == XMLStreamConstants.START_ELEMENT) {
+                if (parser.getLocalName().equals("create")) {
+                    parseCreate();
+                } else if (parser.getLocalName().equals("modify")) {
+                    parseModify();
+                } else if (parser.getLocalName().equals("delete")) {
+                    parseDelete();
+                } else {
+                    parseUnknown();
+                }
+            } else if (event == XMLStreamConstants.END_ELEMENT) {
+                return;
+            }
+        }
+    }
+
+    private void parseDelete() throws XMLStreamException {
+        // Do nothing. If the object has been deleted, do not load it to avoid consistency errors.
+        parseCommon(false);
+    }
+
+    private void parseModify() throws XMLStreamException {
+        parseCommon(true);
+    }
+
+    private void parseCreate() throws XMLStreamException {
+        parseCommon(true);
+    }
+
+    private void parseCommon(boolean keepPrimitive) throws XMLStreamException {
+        while (parser.hasNext()) {
+            int event = parser.next();
+            if (event == XMLStreamConstants.START_ELEMENT) {
+                if (parser.getLocalName().equals("node")) {
+                    if (keepPrimitive) parseNode(); else doNothing();
+                } else if (parser.getLocalName().equals("way")) {
+                    if (keepPrimitive) parseWay(); else doNothing();
+                } else if (parser.getLocalName().equals("relation")) {
+                    if (keepPrimitive) parseRelation(); else doNothing();
+                } else {
+                    parseUnknown();
+                }
+            } else if (event == XMLStreamConstants.END_ELEMENT) {
+                return;
+            }
+        }
+    }
+    
+    private void doNothing() throws XMLStreamException {
+        while (parser.hasNext() && parser.next() != XMLStreamConstants.END_ELEMENT);
+    }
+    
+    /**
+     * Parse the given input source and return the dataset.
+     *
+     * @param source the source input stream. Must not be null.
+     * @param progressMonitor  the progress monitor. If null, {@see NullProgressMonitor#INSTANCE} is assumed
+     *
+     * @return the dataset with the parsed data
+     * @throws IllegalDataException thrown if the an error was found while parsing the data from the source
+     * @throws IllegalArgumentException thrown if source is null
+     */
+    public static DataSet parseDataSet(InputStream source, ProgressMonitor progressMonitor) throws IllegalDataException {
+        return new OsmChangeReader().doParseDataSet(source, progressMonitor);
+    }
+}
Index: trunk/src/org/openstreetmap/josm/io/OsmReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmReader.java	(revision 4529)
+++ trunk/src/org/openstreetmap/josm/io/OsmReader.java	(revision 4530)
@@ -12,9 +12,9 @@
 import java.util.regex.Pattern;
 
+import javax.xml.stream.Location;
 import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLStreamReader;
 import javax.xml.stream.XMLStreamConstants;
 import javax.xml.stream.XMLStreamException;
-import javax.xml.stream.Location;
+import javax.xml.stream.XMLStreamReader;
 
 import org.openstreetmap.josm.data.Bounds;
@@ -48,15 +48,15 @@
 public class OsmReader extends AbstractReader {
 
-    private XMLStreamReader parser;
+    protected XMLStreamReader parser;
 
     /**
-     * constructor (for private use only)
+     * constructor (for private and subclasses use only)
      *
      * @see #parseDataSet(InputStream, DataSet, ProgressMonitor)
      */
-    private OsmReader() {
-    }
-
-    public void setParser(XMLStreamReader parser) {
+    protected OsmReader() {
+    }
+
+    protected void setParser(XMLStreamReader parser) {
         this.parser = parser;
     }
@@ -66,13 +66,9 @@
     }
 
-    public void parse() throws XMLStreamException {
+    protected void parse() throws XMLStreamException {
         int event = parser.getEventType();
         while (true) {
             if (event == XMLStreamConstants.START_ELEMENT) {
-                if (parser.getLocalName().equals("osm") || parser.getLocalName().equals("osmChange")) {
-                    parseOsm();
-                } else {
-                    parseUnkown();
-                }
+                parseRoot();
             } else if (event == XMLStreamConstants.END_ELEMENT) {
                 return;
@@ -85,4 +81,12 @@
         }
         parser.close();
+    }
+    
+    protected void parseRoot() throws XMLStreamException {
+        if (parser.getLocalName().equals("osm")) {
+            parseOsm();
+        } else {
+            parseUnknown();
+        }
     }
 
@@ -115,5 +119,5 @@
                     parseChangeset(uploadChangesetId);
                 } else {
-                    parseUnkown();
+                    parseUnknown();
                 }
             } else if (event == XMLStreamConstants.END_ELEMENT) {
@@ -152,5 +156,5 @@
     }
 
-    private void parseNode() throws XMLStreamException {
+    protected void parseNode() throws XMLStreamException {
         NodeData nd = new NodeData();
         nd.setCoor(new LatLon(Double.parseDouble(parser.getAttributeValue(null, "lat")), Double.parseDouble(parser.getAttributeValue(null, "lon"))));
@@ -166,5 +170,5 @@
                     parseTag(n);
                 } else {
-                    parseUnkown();
+                    parseUnknown();
                 }
             } else if (event == XMLStreamConstants.END_ELEMENT) {
@@ -174,5 +178,5 @@
     }
 
-    private void parseWay() throws XMLStreamException {
+    protected void parseWay() throws XMLStreamException {
         WayData wd = new WayData();
         readCommon(wd);
@@ -191,5 +195,5 @@
                     parseTag(w);
                 } else {
-                    parseUnkown();
+                    parseUnknown();
                 }
             } else if (event == XMLStreamConstants.END_ELEMENT) {
@@ -220,5 +224,5 @@
     }
 
-    private void parseRelation() throws XMLStreamException {
+    protected void parseRelation() throws XMLStreamException {
         RelationData rd = new RelationData();
         readCommon(rd);
@@ -237,5 +241,5 @@
                     parseTag(r);
                 } else {
-                    parseUnkown();
+                    parseUnknown();
                 }
             } else if (event == XMLStreamConstants.END_ELEMENT) {
@@ -293,5 +297,5 @@
                         parseTag(uploadChangeset);
                     } else {
-                        parseUnkown();
+                        parseUnknown();
                     }
                 } else if (event == XMLStreamConstants.END_ELEMENT) {
@@ -314,5 +318,5 @@
     }
 
-    private void parseUnkown(boolean printWarning) throws XMLStreamException {
+    protected void parseUnknown(boolean printWarning) throws XMLStreamException {
         if (printWarning) {
             System.out.println(tr("Undefined element ''{0}'' found in input stream. Skipping.", parser.getLocalName()));
@@ -321,5 +325,5 @@
             int event = parser.next();
             if (event == XMLStreamConstants.START_ELEMENT) {
-                parseUnkown(false); /* no more warning for inner elements */
+                parseUnknown(false); /* no more warning for inner elements */
             } else if (event == XMLStreamConstants.END_ELEMENT) {
                 return;
@@ -328,6 +332,6 @@
     }
 
-    private void parseUnkown() throws XMLStreamException {
-        parseUnkown(true);
+    protected void parseUnknown() throws XMLStreamException {
+        parseUnknown(true);
     }
 
@@ -343,5 +347,5 @@
             int event = parser.next();
             if (event == XMLStreamConstants.START_ELEMENT) {
-                parseUnkown(printWarning);
+                parseUnknown(printWarning);
             } else if (event == XMLStreamConstants.END_ELEMENT) {
                 return;
@@ -531,4 +535,46 @@
     }
 
+    protected DataSet doParseDataSet(InputStream source, ProgressMonitor progressMonitor) throws IllegalDataException {
+        if (progressMonitor == null) {
+            progressMonitor = NullProgressMonitor.INSTANCE;
+        }
+        CheckParameterUtil.ensureParameterNotNull(source, "source");
+        try {
+            progressMonitor.beginTask(tr("Prepare OSM data...", 2));
+            progressMonitor.indeterminateSubTask(tr("Parsing OSM data..."));
+
+            InputStreamReader ir = UTFInputStreamReader.create(source, "UTF-8");
+            XMLStreamReader parser = XMLInputFactory.newInstance().createXMLStreamReader(ir);
+            setParser(parser);
+            parse();
+            progressMonitor.worked(1);
+
+            progressMonitor.indeterminateSubTask(tr("Preparing data set..."));
+            prepareDataSet();
+            progressMonitor.worked(1);
+            return getDataSet();
+        } catch(IllegalDataException e) {
+            throw e;
+        } catch(OsmParsingException e) {
+            throw new IllegalDataException(e.getMessage(), e);
+        } catch(XMLStreamException e) {
+            String msg = e.getMessage();
+            Pattern p = Pattern.compile("Message: (.+)");
+            Matcher m = p.matcher(msg);
+            if (m.find()) {
+                msg = m.group(1);
+            }
+            if (e.getLocation() != null) {
+                throw new IllegalDataException(tr("Line {0} column {1}: ", e.getLocation().getLineNumber(), e.getLocation().getColumnNumber()) + msg, e);
+            } else {
+                throw new IllegalDataException(msg, e);
+            }
+        } catch(Exception e) {
+            throw new IllegalDataException(e);
+        } finally {
+            progressMonitor.finishTask();
+        }
+    }
+    
     /**
      * Parse the given input source and return the dataset.
@@ -542,44 +588,5 @@
      */
     public static DataSet parseDataSet(InputStream source, ProgressMonitor progressMonitor) throws IllegalDataException {
-        if (progressMonitor == null) {
-            progressMonitor = NullProgressMonitor.INSTANCE;
-        }
-        CheckParameterUtil.ensureParameterNotNull(source, "source");
-        OsmReader reader = new OsmReader();
-        try {
-            progressMonitor.beginTask(tr("Prepare OSM data...", 2));
-            progressMonitor.indeterminateSubTask(tr("Parsing OSM data..."));
-
-            InputStreamReader ir = UTFInputStreamReader.create(source, "UTF-8");
-            XMLStreamReader parser = XMLInputFactory.newInstance().createXMLStreamReader(ir);
-            reader.setParser(parser);
-            reader.parse();
-            progressMonitor.worked(1);
-
-            progressMonitor.indeterminateSubTask(tr("Preparing data set..."));
-            reader.prepareDataSet();
-            progressMonitor.worked(1);
-            return reader.getDataSet();
-        } catch(IllegalDataException e) {
-            throw e;
-        } catch(OsmParsingException e) {
-            throw new IllegalDataException(e.getMessage(), e);
-        } catch(XMLStreamException e) {
-            String msg = e.getMessage();
-            Pattern p = Pattern.compile("Message: (.+)");
-            Matcher m = p.matcher(msg);
-            if (m.find()) {
-                msg = m.group(1);
-            }
-            if (e.getLocation() != null) {
-                throw new IllegalDataException(tr("Line {0} column {1}: ", e.getLocation().getLineNumber(), e.getLocation().getColumnNumber()) + msg, e);
-            } else {
-                throw new IllegalDataException(msg, e);
-            }
-        } catch(Exception e) {
-            throw new IllegalDataException(e);
-        } finally {
-            progressMonitor.finishTask();
-        }
+        return new OsmReader().doParseDataSet(source, progressMonitor);
     }
 }
Index: trunk/src/org/openstreetmap/josm/io/OsmServerLocationReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmServerLocationReader.java	(revision 4529)
+++ trunk/src/org/openstreetmap/josm/io/OsmServerLocationReader.java	(revision 4530)
@@ -48,4 +48,35 @@
     }
 
+    /* (non-Javadoc)
+     * @see org.openstreetmap.josm.io.OsmServerReader#parseOsmChange(org.openstreetmap.josm.gui.progress.ProgressMonitor)
+     */
+    @Override
+    public DataSet parseOsmChange(ProgressMonitor progressMonitor)
+            throws OsmTransferException {
+        InputStream in = null;
+        progressMonitor.beginTask(tr("Contacting Server...", 10));
+        try {
+            in = getInputStreamRaw(url, progressMonitor.createSubTaskMonitor(9, false));
+            if (in == null)
+                return null;
+            progressMonitor.subTask(tr("Downloading OSM data..."));
+            return OsmChangeReader.parseDataSet(in, progressMonitor.createSubTaskMonitor(1, false));
+        } catch(OsmTransferException e) {
+            throw e;
+        } catch (Exception e) {
+            if (cancel)
+                return null;
+            throw new OsmTransferException(e);
+        } finally {
+            progressMonitor.finishTask();
+            try {
+                activeConnection = null;
+                if (in != null) {
+                    in.close();
+                }
+            } catch(Exception e) {/* ignore it */}
+        }
+    }
+
     @Override
     public GpxData parseRawGps(ProgressMonitor progressMonitor) throws OsmTransferException {
Index: trunk/src/org/openstreetmap/josm/io/OsmServerReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmServerReader.java	(revision 4529)
+++ trunk/src/org/openstreetmap/josm/io/OsmServerReader.java	(revision 4530)
@@ -142,4 +142,8 @@
     public abstract DataSet parseOsm(ProgressMonitor progressMonitor) throws OsmTransferException;
 
+    public DataSet parseOsmChange(ProgressMonitor progressMonitor) throws OsmTransferException {
+        return null;
+    }
+    
     public GpxData parseRawGps(ProgressMonitor progressMonitor) throws OsmTransferException {
         return null;
