Index: applications/editors/josm/plugins/reverter/src/reverter/ChangesetReverter.java
===================================================================
--- applications/editors/josm/plugins/reverter/src/reverter/ChangesetReverter.java	(revision 21675)
+++ applications/editors/josm/plugins/reverter/src/reverter/ChangesetReverter.java	(revision 21691)
@@ -43,4 +43,11 @@
  */
 public class ChangesetReverter {
+
+    public static enum RevertType {
+        FULL,
+        SELECTION,
+        SELECTION_WITH_UNDELETE
+    }
+
     public final int changesetId;
     public final Changeset changeset;
@@ -120,7 +127,6 @@
         
         // Build our own lists of created/updated/modified objects for better performance
-        Iterator<ChangesetDataSetEntry> iterator = cds.iterator();
-        while (iterator.hasNext()) {
-            ChangesetDataSetEntry entry = iterator.next();
+        for (Iterator<ChangesetDataSetEntry> it = cds.iterator();it.hasNext();) {
+            ChangesetDataSetEntry entry = it.next();
             if (entry.getModificationType() == ChangesetModificationType.CREATED) {
                 created.add(entry.getPrimitive());
@@ -191,4 +197,6 @@
                 p.setDeleted(true);
                 p.setModified(false);
+                ReverterPlugin.undeletedObjects.addPrimitive(ds,
+                        new PrimitiveIdVersion(p.getPrimitiveId(),(int)p.getVersion()));
             }
         }
@@ -280,7 +288,6 @@
         
         // Check objects versions
-        Iterator<ChangesetDataSetEntry> iterator = cds.iterator();
-        while (iterator.hasNext()) {
-            ChangesetDataSetEntry entry = iterator.next();
+        for (Iterator<ChangesetDataSetEntry> it = cds.iterator();it.hasNext();) {
+            ChangesetDataSetEntry entry = it.next();
             HistoryOsmPrimitive hp = entry.getPrimitive();
             OsmPrimitive dp = ds.getPrimitiveById(hp.getPrimitiveId());
@@ -306,7 +313,8 @@
          * isn't going to be deleted or modified, create a conflict.
          */
-        for (OsmPrimitive p : toDelete.toArray(new OsmPrimitive[0])) {
+        for (Iterator<OsmPrimitive> it = toDelete.iterator(); it.hasNext();) {
+            OsmPrimitive p = it.next();
             if (p.isDeleted()) {
-                toDelete.remove(p);
+                it.remove();
                 continue;
             }
@@ -321,5 +329,5 @@
                     conflicted.add(p);
                 }
-                toDelete.remove(p);
+                it.remove();
                 break;
             }
Index: applications/editors/josm/plugins/reverter/src/reverter/ModifiyUploadOrderHook.java
===================================================================
--- applications/editors/josm/plugins/reverter/src/reverter/ModifiyUploadOrderHook.java	(revision 21675)
+++ 	(revision )
@@ -1,49 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package reverter;
-
-import java.util.Collections;
-import java.util.Comparator;
-
-import org.openstreetmap.josm.data.APIDataSet;
-import org.openstreetmap.josm.data.osm.Node;
-import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.data.osm.Relation;
-import org.openstreetmap.josm.data.osm.Way;
-
-import org.openstreetmap.josm.actions.upload.UploadHook;
-
-/**
- * Sort modified objects before uploading in order: nodes, ways, relations
- * It is needed because objects undeleted by reverter is marked as "modified",
- * but in fact they're re-added to JOSM. Without this the "precondition failed"
- * error appears when trying to upload objects undeleted by reverter.
- * 
- */
-public class ModifiyUploadOrderHook implements UploadHook {
-
-    public boolean checkUpload(APIDataSet apiDataSet) {
-        Collections.sort(
-                apiDataSet.getPrimitivesToUpdate(),
-                new Comparator<OsmPrimitive>() {
-                    public int compare(OsmPrimitive o1, OsmPrimitive o2) {
-                        if (o1 instanceof Node && o2 instanceof Node)
-                            return 0;
-                        else if (o1 instanceof Node)
-                            return -1;
-                        else if (o2 instanceof Node)
-                            return 1;
-
-                        if (o1 instanceof Way && o2 instanceof Way)
-                            return 0;
-                        else if (o1 instanceof Way && o2 instanceof Relation)
-                            return -1;
-                        else if (o2 instanceof Way && o1 instanceof Relation)
-                            return 1;
-
-                        return 0;
-                    }
-                }
-                );
-        return true;
-    }
-}
Index: applications/editors/josm/plugins/reverter/src/reverter/PrimitiveIdVersion.java
===================================================================
--- applications/editors/josm/plugins/reverter/src/reverter/PrimitiveIdVersion.java	(revision 21691)
+++ applications/editors/josm/plugins/reverter/src/reverter/PrimitiveIdVersion.java	(revision 21691)
@@ -0,0 +1,53 @@
+package reverter;
+
+import org.openstreetmap.josm.data.osm.PrimitiveId;
+import org.openstreetmap.josm.data.osm.SimplePrimitiveId;
+import org.openstreetmap.josm.tools.CheckParameterUtil;
+
+public class PrimitiveIdVersion {
+    private final PrimitiveId id;
+    private final int version;
+    public PrimitiveIdVersion(PrimitiveId id, int version) {
+        CheckParameterUtil.ensureParameterNotNull(id, "id");
+        this.id = id;
+        this.version = version;
+    }
+
+    public PrimitiveId getPrimitiveId() {
+        return id;
+    }
+
+    public int getVersion() {
+        return version;
+    }
+    
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + id.hashCode();
+        result = prime * result + version;
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        PrimitiveIdVersion other = (PrimitiveIdVersion) obj;
+        if (!id.equals(other.id)) return false;
+        if (version != other.version)
+            return false;
+        return true;
+    }
+
+    @Override
+    public String toString() {
+        return id.toString() + "/" + version;
+    }
+
+}
Index: applications/editors/josm/plugins/reverter/src/reverter/RevertChangesetAction.java
===================================================================
--- applications/editors/josm/plugins/reverter/src/reverter/RevertChangesetAction.java	(revision 21675)
+++ applications/editors/josm/plugins/reverter/src/reverter/RevertChangesetAction.java	(revision 21691)
@@ -75,5 +75,6 @@
                 rev.checkMissingDeleted();
                 // Don't ask user to download primitives going to be undeleted
-                rev.downloadMissingPrimitives(NullProgressMonitor.INSTANCE);
+                rev.downloadMissingPrimitives(progressMonitor.createSubTaskMonitor(0, false));
+                if (progressMonitor.isCancelled()) return;
                 rev.checkMissingCreated();
                 rev.checkMissingUpdated();
Index: applications/editors/josm/plugins/reverter/src/reverter/ReverterPlugin.java
===================================================================
--- applications/editors/josm/plugins/reverter/src/reverter/ReverterPlugin.java	(revision 21675)
+++ applications/editors/josm/plugins/reverter/src/reverter/ReverterPlugin.java	(revision 21691)
@@ -11,16 +11,18 @@
 import org.openstreetmap.josm.actions.UploadAction;
 import org.openstreetmap.josm.gui.MainMenu;
+import org.openstreetmap.josm.gui.MapView;
 import org.openstreetmap.josm.plugins.Plugin;
 import org.openstreetmap.josm.plugins.PluginInformation;
 
 public class ReverterPlugin extends Plugin {
+    static UndeletedObjectsStorage undeletedObjects = new UndeletedObjectsStorage();
     public ReverterPlugin(PluginInformation info) {
         super(info);
-        JMenu historyMenu = Main.main.menu.addMenu(marktr("History"), KeyEvent.VK_R, Main.main.menu.defaultMenuPos,ht("/Plugin/Reverter"));
+        JMenu historyMenu = Main.main.menu.addMenu(marktr("History"), KeyEvent.VK_R,
+                Main.main.menu.defaultMenuPos,ht("/Plugin/Reverter"));
         //MainMenu.add(historyMenu, new ObjectsHistoryAction());       
         MainMenu.add(historyMenu, new RevertChangesetAction());
-        UploadAction.registerUploadHook(new ModifiyUploadOrderHook());
-
-        //TODO: Download deleted objects
+        MapView.addLayerChangeListener(undeletedObjects);
+        UploadAction.registerUploadHook(new ReverterUploadHook(undeletedObjects));        
     }
 }
Index: applications/editors/josm/plugins/reverter/src/reverter/ReverterUploadHook.java
===================================================================
--- applications/editors/josm/plugins/reverter/src/reverter/ReverterUploadHook.java	(revision 21691)
+++ applications/editors/josm/plugins/reverter/src/reverter/ReverterUploadHook.java	(revision 21691)
@@ -0,0 +1,90 @@
+// License: GPL. For details, see LICENSE file.
+package reverter;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map.Entry;
+
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.APIDataSet;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.Way;
+
+import org.openstreetmap.josm.actions.upload.UploadHook;
+
+public class ReverterUploadHook implements UploadHook {
+    private UndeletedObjectsStorage undeletedStorage;
+    
+    public ReverterUploadHook(UndeletedObjectsStorage undeletedStorage) {
+        this.undeletedStorage = undeletedStorage;
+    }
+    
+    public boolean checkUpload(APIDataSet apiDataSet) {
+        // Determine DataSet associated with APIDataSet
+        DataSet ds = null;
+        if (!apiDataSet.getPrimitivesToAdd().isEmpty()) {
+            ds = apiDataSet.getPrimitivesToAdd().get(0).getDataSet();
+        } else if (!apiDataSet.getPrimitivesToUpdate().isEmpty()) {
+            ds = apiDataSet.getPrimitivesToUpdate().get(0).getDataSet();
+        } else if (!apiDataSet.getPrimitivesToDelete().isEmpty()) {
+            ds = apiDataSet.getPrimitivesToDelete().get(0).getDataSet();
+        }
+        if (ds == null) return true;
+        
+        /* Sort modified objects before uploading in order: nodes, ways, relations.
+         * It is needed because objects undeleted by reverter is marked as "modified", but they
+         * cannot be referenced as well as deleted objects. Without this the "precondition failed"
+         * error appears when trying to upload objects undeleted by reverter.
+         */
+        if (undeletedStorage.haveUndeletedObjects(ds)) {
+            Collections.sort(
+                    apiDataSet.getPrimitivesToUpdate(),
+                    new Comparator<OsmPrimitive>() {
+                        public int compare(OsmPrimitive o1, OsmPrimitive o2) {
+                            if (o1 instanceof Node && o2 instanceof Node)
+                                return 0;
+                            else if (o1 instanceof Node)
+                                return -1;
+                            else if (o2 instanceof Node)
+                                return 1;
+            
+                            if (o1 instanceof Way && o2 instanceof Way)
+                                return 0;
+                            else if (o1 instanceof Way && o2 instanceof Relation)
+                                return -1;
+                            else if (o2 instanceof Way && o1 instanceof Relation)
+                                return 1;
+            
+                            return 0;
+                        }
+                    }
+                    );
+        }
+        /* Remove primitives that was undeleted and deleted again from list of primitives
+         * to be deleted.
+         */
+        apiDataSet.getPrimitivesToDelete().removeAll(undeletedStorage.getUndeletedObjects(ds));
+
+        if (apiDataSet.isEmpty()) {
+            JOptionPane.showMessageDialog(
+                    Main.parent,
+                    tr("No changes to upload."),
+                    tr("Warning"),
+                    JOptionPane.INFORMATION_MESSAGE
+            );
+            return false;
+        }
+        return true;
+    }
+}
Index: applications/editors/josm/plugins/reverter/src/reverter/UndeletedObjectsStorage.java
===================================================================
--- applications/editors/josm/plugins/reverter/src/reverter/UndeletedObjectsStorage.java	(revision 21691)
+++ applications/editors/josm/plugins/reverter/src/reverter/UndeletedObjectsStorage.java	(revision 21691)
@@ -0,0 +1,107 @@
+package reverter;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+
+public class UndeletedObjectsStorage implements LayerChangeListener, PropertyChangeListener {
+    private final HashMap<DataSet,HashSet<PrimitiveIdVersion>> undeletedPrimitives =
+        new HashMap<DataSet,HashSet<PrimitiveIdVersion>>();
+
+    public boolean haveUndeletedObjects(DataSet dataSet) {
+        return undeletedPrimitives.containsKey(dataSet);
+    }
+    
+    public void addPrimitive(DataSet dataSet,PrimitiveIdVersion id) {
+        HashSet<PrimitiveIdVersion> set = undeletedPrimitives.get(dataSet);
+        if (set == null) {
+            set = new HashSet<PrimitiveIdVersion>();
+            undeletedPrimitives.put(dataSet, set);
+        }
+        set.add(id);
+    }
+    
+    /**
+     * Checks if primitive still should be treated as "undeleted"
+     * @param dataSet DataSet of the primitive
+     * @param id Id and version of the primitive
+     * @return true if primitive is still should be treated as "undeleted"
+     */
+    private boolean checkPrimitive(DataSet dataSet, PrimitiveIdVersion id) {
+        OsmPrimitive p = dataSet.getPrimitiveById(id.getPrimitiveId());
+        if (p == null) return false;
+        if (p.getVersion() != id.getVersion()) return false;
+        return true;
+    }
+    
+    private void pruneEmptyLayers() {
+        for (Iterator<HashSet<PrimitiveIdVersion>> it =
+                undeletedPrimitives.values().iterator();it.hasNext();) {
+            if (it.next().isEmpty()) it.remove();
+        }
+    }
+    
+    private void pruneLayer(DataSet dataSet) {
+        HashSet<PrimitiveIdVersion> idSet = undeletedPrimitives.get(dataSet);
+        for (Iterator<PrimitiveIdVersion> it = idSet.iterator();it.hasNext();) {
+            if (!checkPrimitive(dataSet,it.next())) it.remove();
+        }
+    }
+    
+    public void pruneObsolete() {
+        for (DataSet ds : undeletedPrimitives.keySet()) {
+            pruneLayer(ds);
+        }
+        pruneEmptyLayers();
+    }
+    
+    public List<OsmPrimitive> getUndeletedObjects(DataSet dataSet) {
+        pruneObsolete();
+        HashSet<PrimitiveIdVersion> idSet = undeletedPrimitives.get(dataSet);
+        if (idSet == null) return null;
+        LinkedList<OsmPrimitive> undeleted = new LinkedList<OsmPrimitive>();
+        for (PrimitiveIdVersion id : idSet) {
+            undeleted.add(dataSet.getPrimitiveById(id.getPrimitiveId()));
+        }
+        return undeleted;
+    }
+    
+    @Override
+    public void activeLayerChange(Layer oldLayer, Layer newLayer) {
+    }
+
+    @Override
+    public void layerAdded(Layer newLayer) {
+        if (!(newLayer instanceof OsmDataLayer)) return;
+        newLayer.addPropertyChangeListener(this);
+    }
+
+    @Override
+    public void layerRemoved(Layer oldLayer) {
+        if (!(oldLayer instanceof OsmDataLayer)) return;
+        oldLayer.addPropertyChangeListener(this);
+        OsmDataLayer dataLayer = (OsmDataLayer)oldLayer;
+        if (undeletedPrimitives.containsKey(dataLayer.data)) {
+            undeletedPrimitives.remove(dataLayer.data);
+        }
+    }
+
+    @Override
+    public void propertyChange(PropertyChangeEvent evt) {
+        if (evt == null) return;
+        if (evt.getPropertyName() == OsmDataLayer.REQUIRES_UPLOAD_TO_SERVER_PROP &&
+                evt.getOldValue().equals(true) && evt.getNewValue().equals(false)) {
+            pruneObsolete();
+        }
+    }
+}
