Index: trunk/src/org/openstreetmap/josm/Main.java
===================================================================
--- trunk/src/org/openstreetmap/josm/Main.java	(revision 2612)
+++ trunk/src/org/openstreetmap/josm/Main.java	(revision 2613)
@@ -188,4 +188,5 @@
             map.mapView.removeLayer(layer);
             if (map.mapView.getAllLayers().isEmpty()) {
+                map.tearDownDialogsPane();
                 setMapFrame(null);
             }
Index: trunk/src/org/openstreetmap/josm/actions/CloseChangesetAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/CloseChangesetAction.java	(revision 2612)
+++ trunk/src/org/openstreetmap/josm/actions/CloseChangesetAction.java	(revision 2613)
@@ -2,6 +2,6 @@
 package org.openstreetmap.josm.actions;
 
+import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
 import static org.openstreetmap.josm.tools.I18n.tr;
-import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
 
 import java.awt.event.ActionEvent;
@@ -16,4 +16,5 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.osm.Changeset;
+import org.openstreetmap.josm.data.osm.ChangesetCache;
 import org.openstreetmap.josm.data.osm.UserInfo;
 import org.openstreetmap.josm.gui.ExceptionDialogUtil;
@@ -49,8 +50,6 @@
     }
 
-    protected void onPostDownloadOpenChangesets(DownloadOpenChangesetsTask task) {
-        if (task.isCancelled() || task.getLastException() != null) return;
-
-        List<Changeset> openChangesets = task.getChangesets();
+    protected void onPostDownloadOpenChangesets() {
+        List<Changeset> openChangesets = ChangesetCache.getInstance().getOpenChangesets();
         if (openChangesets.isEmpty()) {
             JOptionPane.showMessageDialog(
@@ -105,5 +104,8 @@
                                 ExceptionDialogUtil.explainException(lastException);
                             }
-                            onPostDownloadOpenChangesets(DownloadOpenChangesetsTask.this);
+                            ChangesetCache.getInstance().update(changesets);
+                            if (!cancelled && lastException == null) {
+                                onPostDownloadOpenChangesets();
+                            }
                         }
                     }
@@ -146,8 +148,4 @@
         }
 
-        public List<Changeset> getChangesets() {
-            return changesets;
-        }
-
         public Exception getLastException() {
             return lastException;
Index: trunk/src/org/openstreetmap/josm/data/osm/Changeset.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/Changeset.java	(revision 2612)
+++ trunk/src/org/openstreetmap/josm/data/osm/Changeset.java	(revision 2613)
@@ -7,4 +7,5 @@
 import java.util.Map;
 
+import org.openstreetmap.josm.data.Bounds;
 import org.openstreetmap.josm.data.coor.LatLon;
 import org.openstreetmap.josm.data.osm.visitor.Visitor;
@@ -68,19 +69,10 @@
             setId(other.getId());
             this.incomplete = true;
+            this.tags = new HashMap<String, String>();
         } else {
-            cloneFrom(other);
+            this.id = other.id;
+            mergeFrom(other);
             this.incomplete = false;
         }
-    }
-
-    public void cloneFrom(Changeset other) {
-        setId(other.getId());
-        setUser(other.getUser());
-        setCreatedAt(other.getCreatedAt());
-        setClosedAt(other.getClosedAt());
-        setMin(other.getMin());
-        setMax(other.getMax());
-        setKeys(other.getKeys());
-        setOpen(other.isOpen());
     }
 
@@ -152,4 +144,10 @@
     public LatLon getMax() {
         return max;
+    }
+
+    public Bounds getBounds() {
+        if (min != null && max != null)
+            return new Bounds(min,max);
+        return null;
     }
 
@@ -237,12 +235,6 @@
         if (id > 0)
             return prime * result + getClass().hashCode();
-        result = prime * result + ((closedAt == null) ? 0 : closedAt.hashCode());
-        result = prime * result + ((createdAt == null) ? 0 : createdAt.hashCode());
-        result = prime * result + ((max == null) ? 0 : max.hashCode());
-        result = prime * result + ((min == null) ? 0 : min.hashCode());
-        result = prime * result + (open ? 1231 : 1237);
-        result = prime * result + ((tags == null) ? 0 : tags.hashCode());
-        result = prime * result + ((user == null) ? 0 : user.hashCode());
-        return result;
+        else
+            return super.hashCode();
     }
 
@@ -258,39 +250,5 @@
         if (this.id > 0 && other.id == this.id)
             return true;
-        if (closedAt == null) {
-            if (other.closedAt != null)
-                return false;
-        } else if (!closedAt.equals(other.closedAt))
-            return false;
-        if (createdAt == null) {
-            if (other.createdAt != null)
-                return false;
-        } else if (!createdAt.equals(other.createdAt))
-            return false;
-        if (id != other.id)
-            return false;
-        if (max == null) {
-            if (other.max != null)
-                return false;
-        } else if (!max.equals(other.max))
-            return false;
-        if (min == null) {
-            if (other.min != null)
-                return false;
-        } else if (!min.equals(other.min))
-            return false;
-        if (open != other.open)
-            return false;
-        if (tags == null) {
-            if (other.tags != null)
-                return false;
-        } else if (!tags.equals(other.tags))
-            return false;
-        if (user == null) {
-            if (other.user != null)
-                return false;
-        } else if (!user.equals(other.user))
-            return false;
-        return true;
+        return this == obj;
     }
 
@@ -318,6 +276,6 @@
         this.min = other.min;
         this.max = other.max;
-        this.tags.clear();
-        this.tags.putAll(other.tags);
+        this.tags = new HashMap<String, String>(other.tags);
+        this.incomplete = other.incomplete;
     }
 }
Index: trunk/src/org/openstreetmap/josm/data/osm/ChangesetCache.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/ChangesetCache.java	(revision 2613)
+++ trunk/src/org/openstreetmap/josm/data/osm/ChangesetCache.java	(revision 2613)
@@ -0,0 +1,137 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.osm;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.logging.Logger;
+
+public class ChangesetCache {
+    static private final Logger logger = Logger.getLogger(ChangesetCache.class.getName());
+    static private final ChangesetCache instance = new ChangesetCache();
+
+    public static ChangesetCache getInstance() {
+        return instance;
+    }
+
+    private final Map<Integer, Changeset> cache  = new HashMap<Integer, Changeset>();
+
+    private final CopyOnWriteArrayList<ChangesetCacheListener> listeners =
+        new CopyOnWriteArrayList<ChangesetCacheListener>();
+
+    private ChangesetCache() {
+    }
+
+    public void addChangesetCacheListener(ChangesetCacheListener listener) {
+        synchronized(listeners) {
+            if (listener != null && ! listeners.contains(listener)) {
+                listeners.add(listener);
+            }
+        }
+    }
+
+    public void removeChangesetCacheListener(ChangesetCacheListener listener) {
+        synchronized(listeners) {
+            if (listener != null && listeners.contains(listener)) {
+                listeners.remove(listener);
+            }
+        }
+    }
+
+    protected void fireChangesetCacheEvent(ChangesetCacheEvent e) {
+        for(ChangesetCacheListener l: listeners) {
+            l.changesetCacheUpdated(e);
+        }
+    }
+
+    protected void update(Changeset cs, DefaultChangesetCacheEvent e) {
+        if (cs == null) return;
+        if (cs.isNew()) return;
+        Changeset inCache = cache.get(cs.getId());
+        if (inCache != null) {
+            inCache.mergeFrom(cs);
+            e.rememberUpdatedChangeset(inCache);
+        } else {
+            e.rememberAddedChangeset(cs);
+            cache.put(cs.getId(), cs);
+        }
+    }
+
+    public void update(Changeset cs) {
+        DefaultChangesetCacheEvent e = new DefaultChangesetCacheEvent(this);
+        update(cs, e);
+        fireChangesetCacheEvent(e);
+    }
+
+    public void update(Collection<Changeset> changesets) {
+        if (changesets == null || changesets.isEmpty()) return;
+        DefaultChangesetCacheEvent e = new DefaultChangesetCacheEvent(this);
+        for (Changeset cs: changesets) {
+            update(cs, e);
+        }
+        fireChangesetCacheEvent(e);
+    }
+
+    public boolean contains(int id) {
+        if (id <=0) return false;
+        return cache.get(id) != null;
+    }
+
+    public boolean contains(Changeset cs) {
+        if (cs == null) return false;
+        if (cs.isNew()) return false;
+        return contains(cs.getId());
+    }
+
+    public Changeset get(int id) {
+        return cache.get(id);
+    }
+
+    protected void remove(int id, DefaultChangesetCacheEvent e) {
+        if (id <= 0) return;
+        Changeset cs = cache.get(id);
+        if (cs == null) return;
+        cache.remove(id);
+        e.rememberRemovedChangeset(cs);
+    }
+
+    public void remove(int id) {
+        DefaultChangesetCacheEvent e = new DefaultChangesetCacheEvent(this);
+        remove(id, e);
+        if (! e.isEmpty()) {
+            fireChangesetCacheEvent(e);
+        }
+    }
+
+    public void remove(Changeset cs) {
+        if (cs == null) return;
+        if (cs.isNew()) return;
+        remove(cs.getId());
+    }
+
+    public int size() {
+        return cache.size();
+    }
+
+    public void clear() {
+        DefaultChangesetCacheEvent e = new DefaultChangesetCacheEvent(this);
+        for (Changeset cs: cache.values()) {
+            e.rememberRemovedChangeset(cs);
+        }
+        cache.clear();
+        fireChangesetCacheEvent(e);
+    }
+
+    public List<Changeset> getOpenChangesets() {
+        List<Changeset> ret = new ArrayList<Changeset>();
+        for (Changeset cs: cache.values()) {
+            if (cs.isOpen()) {
+                ret.add(cs);
+            }
+        }
+        return ret;
+    }
+}
Index: trunk/src/org/openstreetmap/josm/data/osm/ChangesetCacheEvent.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/ChangesetCacheEvent.java	(revision 2613)
+++ trunk/src/org/openstreetmap/josm/data/osm/ChangesetCacheEvent.java	(revision 2613)
@@ -0,0 +1,12 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.osm;
+
+import java.util.Collection;
+
+public interface ChangesetCacheEvent {
+    ChangesetCache getSource();
+    Collection<Changeset> getAddedChangesets();
+    Collection<Changeset> getRemovedChangesets();
+    Collection<Changeset> getUpdatedChangesets();
+
+}
Index: trunk/src/org/openstreetmap/josm/data/osm/ChangesetCacheListener.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/ChangesetCacheListener.java	(revision 2613)
+++ trunk/src/org/openstreetmap/josm/data/osm/ChangesetCacheListener.java	(revision 2613)
@@ -0,0 +1,8 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.osm;
+
+
+public interface ChangesetCacheListener {
+
+    void changesetCacheUpdated(ChangesetCacheEvent event);
+}
Index: trunk/src/org/openstreetmap/josm/data/osm/DataSet.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 2612)
+++ trunk/src/org/openstreetmap/josm/data/osm/DataSet.java	(revision 2613)
@@ -20,4 +20,5 @@
 
 import org.openstreetmap.josm.data.SelectionChangedListener;
+
 
 /**
Index: trunk/src/org/openstreetmap/josm/data/osm/DefaultChangesetCacheEvent.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/osm/DefaultChangesetCacheEvent.java	(revision 2613)
+++ trunk/src/org/openstreetmap/josm/data/osm/DefaultChangesetCacheEvent.java	(revision 2613)
@@ -0,0 +1,54 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.data.osm;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+public class DefaultChangesetCacheEvent implements ChangesetCacheEvent{
+
+    private final Set<Changeset> added;
+    private final Set<Changeset> modified;
+    private final Set<Changeset> removed;
+    private final ChangesetCache source;
+
+    public DefaultChangesetCacheEvent(ChangesetCache source) {
+        this.source = source;
+        added = new HashSet<Changeset>();
+        modified = new HashSet<Changeset>();
+        removed = new HashSet<Changeset>();
+    }
+
+    public Collection<Changeset> getAddedChangesets() {
+        return Collections.unmodifiableCollection(added);
+    }
+    public Collection<Changeset> getRemovedChangesets() {
+        return Collections.unmodifiableCollection(removed);
+    }
+    public ChangesetCache getSource() {
+        return source;
+    }
+    public Collection<Changeset> getUpdatedChangesets() {
+        return Collections.unmodifiableCollection(modified);
+    }
+
+    public void rememberAddedChangeset(Changeset cs) {
+        if (cs == null) return;
+        added.add(cs);
+    }
+
+    public void rememberUpdatedChangeset(Changeset cs) {
+        if (cs == null) return;
+        modified.add(cs);
+    }
+
+    public void rememberRemovedChangeset(Changeset cs) {
+        if (cs == null) return;
+        removed.add(cs);
+    }
+
+    public boolean isEmpty() {
+        return added.isEmpty() && modified.isEmpty() && removed.isEmpty();
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/MapFrame.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/MapFrame.java	(revision 2612)
+++ trunk/src/org/openstreetmap/josm/gui/MapFrame.java	(revision 2613)
@@ -4,9 +4,8 @@
 
 import java.awt.BorderLayout;
-import java.awt.Component;
 import java.awt.Container;
 import java.awt.Dimension;
+import java.awt.event.MouseWheelEvent;
 import java.awt.event.MouseWheelListener;
-import java.awt.event.MouseWheelEvent;
 import java.util.ArrayList;
 import java.util.List;
@@ -16,10 +15,10 @@
 import javax.swing.BoxLayout;
 import javax.swing.ButtonGroup;
+import javax.swing.JPanel;
 import javax.swing.JSplitPane;
-import javax.swing.JPanel;
 import javax.swing.JToolBar;
 import javax.swing.border.Border;
+import javax.swing.plaf.basic.BasicSplitPaneDivider;
 import javax.swing.plaf.basic.BasicSplitPaneUI;
-import javax.swing.plaf.basic.BasicSplitPaneDivider;
 
 import org.openstreetmap.josm.Main;
@@ -30,4 +29,5 @@
 import org.openstreetmap.josm.actions.mapmode.SelectAction;
 import org.openstreetmap.josm.actions.mapmode.ZoomAction;
+import org.openstreetmap.josm.gui.dialogs.ChangesetDialog;
 import org.openstreetmap.josm.gui.dialogs.CommandStackDialog;
 import org.openstreetmap.josm.gui.dialogs.ConflictDialog;
@@ -126,6 +126,8 @@
         splitPane.setBorder(null);
         splitPane.setUI(new BasicSplitPaneUI() {
+            @Override
             public BasicSplitPaneDivider createDefaultDivider() {
                 return new BasicSplitPaneDivider(this) {
+                    @Override
                     public void setBorder(Border b) {
                     }
@@ -148,10 +150,12 @@
         addToggleDialog(new HistoryDialog());
         addToggleDialog(new SelectionListDialog());
-        if(Main.pref.getBoolean("displayfilter", false))
+        if(Main.pref.getBoolean("displayfilter", false)) {
             addToggleDialog(new FilterDialog());
+        }
         addToggleDialog(new UserListDialog());
         addToggleDialog(conflictDialog = new ConflictDialog());
         addToggleDialog(new CommandStackDialog(this));
         addToggleDialog(relationListDialog = new RelationListDialog());
+        addToggleDialog(new ChangesetDialog(this));
 
         // status line below the map
@@ -209,4 +213,11 @@
     public void initializeDialogsPane() {
         dialogsPanel.initialize(allDialogs);
+    }
+
+    /**
+     * 
+     */
+    public void tearDownDialogsPane() {
+        dialogsPanel.tearDown();
     }
 
Index: trunk/src/org/openstreetmap/josm/gui/PleaseWaitRunnable.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/PleaseWaitRunnable.java	(revision 2612)
+++ trunk/src/org/openstreetmap/josm/gui/PleaseWaitRunnable.java	(revision 2613)
@@ -2,9 +2,7 @@
 package org.openstreetmap.josm.gui;
 
-import static org.openstreetmap.josm.tools.I18n.tr;
-
 import java.awt.EventQueue;
-import java.io.FileNotFoundException;
 import java.io.IOException;
+import java.util.logging.Logger;
 
 import javax.swing.SwingUtilities;
@@ -23,4 +21,5 @@
  */
 public abstract class PleaseWaitRunnable implements Runnable, CancelListener {
+    private final static Logger logger = Logger.getLogger(PleaseWaitRunnable.class.getName());
 
     private boolean cancelled = false;
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/ChangesetDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/ChangesetDialog.java	(revision 2613)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/ChangesetDialog.java	(revision 2613)
@@ -0,0 +1,293 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.dialogs;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.BorderLayout;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ItemEvent;
+import java.awt.event.ItemListener;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import javax.swing.AbstractAction;
+import javax.swing.DefaultListSelectionModel;
+import javax.swing.JCheckBox;
+import javax.swing.JList;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JToolBar;
+import javax.swing.ListSelectionModel;
+import javax.swing.SwingUtilities;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.osm.ChangesetCache;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.gui.MapFrame;
+import org.openstreetmap.josm.gui.dialogs.changeset.ChangesetInSelectionListModel;
+import org.openstreetmap.josm.gui.dialogs.changeset.ChangesetListCellRenderer;
+import org.openstreetmap.josm.gui.dialogs.changeset.ChangesetListModel;
+import org.openstreetmap.josm.gui.dialogs.changeset.ChangesetsInActiveDataLayerListModel;
+import org.openstreetmap.josm.gui.dialogs.changeset.DownloadChangesetsTask;
+import org.openstreetmap.josm.gui.help.HelpUtil;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.tools.ImageProvider;
+
+public class ChangesetDialog extends ToggleDialog{
+    static private final Logger logger = Logger.getLogger(ChangesetDialog.class.getName());
+
+    private ChangesetInSelectionListModel inSelectionModel;
+    private ChangesetsInActiveDataLayerListModel inActiveDataLayerModel;
+    private JList lstInSelection;
+    private JList lstInActiveDataLayer;
+    private JCheckBox cbInSelectionOnly;
+    private JPanel pnlList;
+
+    protected void buildChangesetsLists() {
+        DefaultListSelectionModel selectionModel = new DefaultListSelectionModel();
+        inSelectionModel = new ChangesetInSelectionListModel(selectionModel);
+
+        lstInSelection = new JList(inSelectionModel);
+        lstInSelection.setSelectionModel(selectionModel);
+        lstInSelection.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
+        lstInSelection.setCellRenderer(new ChangesetListCellRenderer());
+
+        selectionModel = new DefaultListSelectionModel();
+        inActiveDataLayerModel = new ChangesetsInActiveDataLayerListModel(selectionModel);
+        lstInActiveDataLayer = new JList(inActiveDataLayerModel);
+        lstInActiveDataLayer.setSelectionModel(selectionModel);
+        lstInActiveDataLayer.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
+        lstInActiveDataLayer.setCellRenderer(new ChangesetListCellRenderer());
+
+        ChangesetCache.getInstance().addChangesetCacheListener(inSelectionModel);
+        Layer.listeners.add(inSelectionModel);
+        DataSet.selListeners.add(inSelectionModel);
+
+        ChangesetCache.getInstance().addChangesetCacheListener(inActiveDataLayerModel);
+        Layer.listeners.add(inActiveDataLayerModel);
+
+        DblClickHandler dblClickHandler = new DblClickHandler();
+        lstInSelection.addMouseListener(dblClickHandler);
+        lstInActiveDataLayer.addMouseListener(dblClickHandler);
+    }
+
+    @Override
+    public void tearDown() {
+        ChangesetCache.getInstance().removeChangesetCacheListener(inActiveDataLayerModel);
+        Layer.listeners.remove(inSelectionModel);
+        DataSet.selListeners.remove(inSelectionModel);
+        Layer.listeners.remove(inActiveDataLayerModel);
+    }
+
+    protected JPanel buildFilterPanel() {
+        JPanel pnl = new JPanel(new FlowLayout(FlowLayout.LEFT));
+        pnl.setBorder(null);
+        pnl.add(cbInSelectionOnly = new JCheckBox(tr("For selected objects only")));
+        cbInSelectionOnly.setToolTipText(tr("<html>Select to show changesets for the currently selected objects only.<br>"
+                + "Unselect to show all changesets for objects in the current data layer.</html>"));
+        cbInSelectionOnly.setSelected(Main.pref.getBoolean("changeset-dialog.for-selected-objects-only", false));
+        return pnl;
+    }
+
+    protected JPanel buildListPanel() {
+        buildChangesetsLists();
+        JPanel pnl = new JPanel(new BorderLayout());
+        if (cbInSelectionOnly.isSelected()) {
+            pnl.add(new JScrollPane(lstInSelection));
+        } else {
+            pnl.add(new JScrollPane(lstInActiveDataLayer));
+        }
+        return pnl;
+    }
+
+    protected JPanel buildButtonPanel() {
+        JPanel pnl = new JPanel(new FlowLayout(FlowLayout.LEFT));
+
+        JToolBar tp = new JToolBar(JToolBar.HORIZONTAL);
+        tp.setFloatable(false);
+
+        SelectObjectsAction selectObjectsAction = new SelectObjectsAction();
+        tp.add(selectObjectsAction);
+        cbInSelectionOnly.addItemListener(selectObjectsAction);
+        lstInActiveDataLayer.getSelectionModel().addListSelectionListener(selectObjectsAction);
+        lstInSelection.getSelectionModel().addListSelectionListener(selectObjectsAction);
+
+        ReadChangesetsAction readChangesetAction = new ReadChangesetsAction();
+        tp.add(readChangesetAction);
+        cbInSelectionOnly.addItemListener(readChangesetAction);
+        lstInActiveDataLayer.getSelectionModel().addListSelectionListener(readChangesetAction);
+        lstInSelection.getSelectionModel().addListSelectionListener(readChangesetAction);
+
+        pnl.add(tp);
+        return pnl;
+    }
+
+    protected void build() {
+        JPanel pnl = new JPanel(new BorderLayout());
+        pnl.add(buildFilterPanel(), BorderLayout.NORTH);
+        pnl.add(pnlList = buildListPanel(), BorderLayout.CENTER);
+        pnl.add(buildButtonPanel(), BorderLayout.SOUTH);
+        add(pnl, BorderLayout.CENTER);
+
+        cbInSelectionOnly.addItemListener(new FilterChangeHandler());
+
+        HelpUtil.setHelpContext(pnl, HelpUtil.ht("/Dialog/ChangesetListDialog"));
+    }
+
+    protected JList getCurrentChangesetList() {
+        if (cbInSelectionOnly.isSelected())
+            return lstInSelection;
+        return lstInActiveDataLayer;
+    }
+
+    protected ChangesetListModel getCurrentChangesetListModel() {
+        if (cbInSelectionOnly.isSelected())
+            return inSelectionModel;
+        return inActiveDataLayerModel;
+    }
+
+    protected void initWithCurrentData() {
+        if (Main.main.getEditLayer() != null) {
+            inSelectionModel.initFromPrimitives(Main.main.getEditLayer().data.getSelected());
+            inActiveDataLayerModel.initFromDataSet(Main.main.getEditLayer().data);
+        }
+    }
+
+    public ChangesetDialog(MapFrame mapFrame) {
+        super(
+                tr("Changesets"),
+                "changesetdialog",
+                tr("Open the list of changesets in the current layer."),
+                null, /* no keyboard shortcut */
+                200, /* the preferred height */
+                false /* don't show if there is no preference */
+        );
+        build();
+        initWithCurrentData();
+    }
+
+    class DblClickHandler extends MouseAdapter {
+        @Override
+        public void mouseClicked(MouseEvent e) {
+            if (!SwingUtilities.isLeftMouseButton(e) || e.getClickCount() < 2)
+                return;
+            Set<Integer> sel = getCurrentChangesetListModel().getSelectedChangesetIds();
+            if (sel.isEmpty())
+                return;
+            if (Main.main.getCurrentDataSet() == null)
+                return;
+            new SelectObjectsAction().selectObjectsByChangesetIds(Main.main.getCurrentDataSet(), sel);
+        }
+
+    }
+
+    class FilterChangeHandler implements ItemListener {
+        public void itemStateChanged(ItemEvent e) {
+            Main.pref.put("changeset-dialog.for-selected-objects-only", cbInSelectionOnly.isSelected());
+            pnlList.removeAll();
+            if (cbInSelectionOnly.isSelected()) {
+                pnlList.add(new JScrollPane(lstInSelection), BorderLayout.CENTER);
+            } else {
+                pnlList.add(new JScrollPane(lstInActiveDataLayer), BorderLayout.CENTER);
+            }
+            validate();
+            repaint();
+        }
+    }
+
+    class SelectObjectsAction extends AbstractAction implements ListSelectionListener, ItemListener{
+
+        public SelectObjectsAction() {
+            putValue(NAME, tr("Select"));
+            putValue(SHORT_DESCRIPTION, tr("Select all objects assigned to the currently selected changesets"));
+            putValue(SMALL_ICON, ImageProvider.get("dialogs", "select"));
+            updateEnabledState();
+        }
+
+        public void selectObjectsByChangesetIds(DataSet ds, Set<Integer> ids) {
+            if (ds == null || ids == null)
+                return;
+            Set<OsmPrimitive> sel = new HashSet<OsmPrimitive>();
+            for (OsmPrimitive p: ds.getNodes()) {
+                if (ids.contains(p.getChangesetId())) {
+                    sel.add(p);
+                }
+            }
+            for (OsmPrimitive p: ds.getWays()) {
+                if (ids.contains(p.getChangesetId())) {
+                    sel.add(p);
+                }
+            }
+            for (OsmPrimitive p: ds.getRelations()) {
+                if (ids.contains(p.getChangesetId())) {
+                    sel.add(p);
+                }
+            }
+            ds.setSelected(sel);
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            if (Main.main.getEditLayer() == null)
+                return;
+            ChangesetListModel model = getCurrentChangesetListModel();
+            Set<Integer> sel = model.getSelectedChangesetIds();
+            if (sel.isEmpty())
+                return;
+
+            DataSet ds = Main.main.getEditLayer().data;
+            selectObjectsByChangesetIds(ds,sel);
+        }
+
+        protected void updateEnabledState() {
+            setEnabled(getCurrentChangesetList().getSelectedIndices().length > 0);
+        }
+
+        public void itemStateChanged(ItemEvent arg0) {
+            updateEnabledState();
+
+        }
+
+        public void valueChanged(ListSelectionEvent e) {
+            updateEnabledState();
+        }
+    }
+
+    class ReadChangesetsAction extends AbstractAction implements ListSelectionListener, ItemListener{
+        public ReadChangesetsAction() {
+            putValue(NAME, tr("Download"));
+            putValue(SHORT_DESCRIPTION, tr("Download information about the selected changesets from the OSM server"));
+            putValue(SMALL_ICON, ImageProvider.get("download"));
+            updateEnabledState();
+        }
+
+        public void actionPerformed(ActionEvent arg0) {
+            ChangesetListModel model = getCurrentChangesetListModel();
+            Set<Integer> sel = model.getSelectedChangesetIds();
+            if (sel.isEmpty())
+                return;
+            DownloadChangesetsTask task = new DownloadChangesetsTask(sel);
+            Main.worker.submit(task);
+        }
+
+        protected void updateEnabledState() {
+            setEnabled(getCurrentChangesetList().getSelectedIndices().length > 0);
+        }
+
+        public void itemStateChanged(ItemEvent arg0) {
+            updateEnabledState();
+
+        }
+
+        public void valueChanged(ListSelectionEvent e) {
+            updateEnabledState();
+        }
+    }
+
+}
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/DialogsPanel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/DialogsPanel.java	(revision 2612)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/DialogsPanel.java	(revision 2613)
@@ -33,5 +33,5 @@
 
     public boolean initialized = false; // read only from outside
-    
+
     public void initialize(List<ToggleDialog> pAllDialogs) {
         if (initialized)
@@ -43,13 +43,24 @@
             add(pAllDialogs.get(i), false);
         }
-        
+
         this.add(mSpltPane);
         reconstruct(Action.ELEMENT_SHRINKS, null);
     }
 
+    /**
+     * Invoke before the panel is discarded. This will in turn call {@see ToggleDialog#tearDown()}
+     * on every dialog.
+     * 
+     */
+    public void tearDown() {
+        for(ToggleDialog dialog: allDialogs) {
+            dialog.tearDown();
+        }
+    }
+
     public void add(ToggleDialog dlg) {
         add(dlg, true);
     }
-    
+
     public void add(ToggleDialog dlg, boolean doReconstruct) {
         allDialogs.add(dlg);
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/ToggleDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/ToggleDialog.java	(revision 2612)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/ToggleDialog.java	(revision 2613)
@@ -68,5 +68,5 @@
      */
     protected boolean isCollapsed;
-    
+
     /** the preferred height if the toggle dialog is expanded */
     private int preferredHeight;
@@ -120,5 +120,4 @@
         isDocked = Main.pref.getBoolean(preferencePrefix+".docked", true);
         isCollapsed = Main.pref.getBoolean(preferencePrefix+".minimized", false);
-        //System.err.println(name+": showing="+isShowing+" docked="+isDocked+" collapsed="+isCollapsed);
     }
 
@@ -214,5 +213,5 @@
      */
     public void collapse() {
-//        if (isShowing && isDocked && !isCollapsed) {
+        //        if (isShowing && isDocked && !isCollapsed) {
         if (isDialogInDefaultView()) {
             setContentVisible(false);
@@ -231,5 +230,5 @@
      */
     protected void expand() {
-//        if (isShowing && isDocked && isCollapsed) {
+        //        if (isShowing && isDocked && isCollapsed) {
         if (isDialogInCollapsedView()) {
             setContentVisible(true);
@@ -529,6 +528,6 @@
 
     /**
-    * Change the Geometry of the detached dialog to better fit the content.
-    */
+     * Change the Geometry of the detached dialog to better fit the content.
+     */
     protected Rectangle getDetachedGeometry(Rectangle last) {
         return last;
@@ -552,5 +551,5 @@
         return true;
     }
-    
+
     /**
      * primitive stateChangedListener for subclasses
@@ -559,6 +558,14 @@
     }
 
-    /***
-     * End of override hooks
-     **/
+    /**
+     * This method is called by hosting panel before the panel with the toggle dialogs
+     * and the toggle dialogs themself are discared, for instance because no layer is
+     * left in JOSM and  the main screen turns from the map editor to the MOTD panel.
+     * 
+     * Override in subclasses to unregister as listener. After tearDown() is invoked
+     * the dialog should be registered as listener.
+     * 
+     * The default implementation is empty.
+     */
+    public void tearDown() {}
 }
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetInSelectionListModel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetInSelectionListModel.java	(revision 2613)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetInSelectionListModel.java	(revision 2613)
@@ -0,0 +1,38 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.dialogs.changeset;
+
+import java.util.Collection;
+
+import javax.swing.DefaultListSelectionModel;
+
+import org.openstreetmap.josm.data.SelectionChangedListener;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.gui.layer.Layer.LayerChangeListener;
+
+public class ChangesetInSelectionListModel extends ChangesetListModel implements SelectionChangedListener, LayerChangeListener{
+
+    public ChangesetInSelectionListModel(DefaultListSelectionModel selectionModel) {
+        super(selectionModel);
+    }
+    /* ---------------------------------------------------------------------------- */
+    /* Interface SelectionChangeListener                                            */
+    /* ---------------------------------------------------------------------------- */
+    public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
+        initFromPrimitives(newSelection);
+    }
+
+    /* ---------------------------------------------------------------------------- */
+    /* Interface LayerChangeListener                                                */
+    /* ---------------------------------------------------------------------------- */
+    public void activeLayerChange(Layer oldLayer, Layer newLayer) {
+        if (newLayer == null || ! (newLayer instanceof OsmDataLayer)) {
+            setChangesets(null);
+        } else if (newLayer instanceof OsmDataLayer){
+            initFromPrimitives(((OsmDataLayer) newLayer).data.getSelected());
+        }
+    }
+    public void layerAdded(Layer newLayer) {}
+    public void layerRemoved(Layer oldLayer) {}
+}
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetListCellRenderer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetListCellRenderer.java	(revision 2613)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetListCellRenderer.java	(revision 2613)
@@ -0,0 +1,56 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.dialogs.changeset;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Component;
+
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.ListCellRenderer;
+import javax.swing.UIManager;
+
+import org.openstreetmap.josm.data.osm.Changeset;
+import org.openstreetmap.josm.tools.ImageProvider;
+
+public class ChangesetListCellRenderer extends JLabel implements ListCellRenderer{
+
+    public ChangesetListCellRenderer() {
+        setOpaque(true);
+        setIcon(ImageProvider.get("data", "changeset"));
+    }
+
+    protected void renderColors(boolean selected) {
+        if (selected) {
+            setForeground(UIManager.getColor("List.selectionForeground"));
+            setBackground(UIManager.getColor("List.selectionBackground"));
+        } else {
+            setForeground(UIManager.getColor("List.foreground"));
+            setBackground(UIManager.getColor("List.background"));
+        }
+    }
+
+    protected void renderLabel(Changeset cs) {
+        StringBuffer sb = new StringBuffer();
+        if (cs.isIncomplete()) {
+            sb.append(tr("{0} [incomplete]", cs.getId()));
+        } else {
+            String comment = cs.get("comment");
+            sb.append(cs.getId());
+            sb.append(" - ");
+            sb.append(cs.isOpen() ? tr("open") : tr("closed"));
+            if (comment != null) {
+                sb.append(" - ").append("'").append(comment).append("'");
+            }
+        }
+        setText(sb.toString());
+    }
+
+    public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
+            boolean cellHasFocus) {
+        Changeset cs = (Changeset)value;
+        renderColors(isSelected);
+        renderLabel(cs);
+        return this;
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetListModel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetListModel.java	(revision 2613)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetListModel.java	(revision 2613)
@@ -0,0 +1,191 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.dialogs.changeset;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.logging.Logger;
+
+import javax.swing.DefaultListModel;
+import javax.swing.DefaultListSelectionModel;
+
+import org.openstreetmap.josm.data.osm.Changeset;
+import org.openstreetmap.josm.data.osm.ChangesetCache;
+import org.openstreetmap.josm.data.osm.ChangesetCacheEvent;
+import org.openstreetmap.josm.data.osm.ChangesetCacheListener;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+
+public class ChangesetListModel extends DefaultListModel  implements ChangesetCacheListener{
+    static private final Logger logger = Logger.getLogger(ChangesetListModel.class.getName());
+
+    private final List<Changeset> data = new ArrayList<Changeset>();
+    private DefaultListSelectionModel selectionModel;
+
+    public ChangesetListModel(DefaultListSelectionModel selectionModel) {
+        this.selectionModel = selectionModel;
+    }
+
+    public Set<Changeset> getSelectedChangesets() {
+        Set<Changeset> ret = new HashSet<Changeset>();
+        for (int i=0; i < getSize(); i++) {
+            if (selectionModel.isSelectedIndex(i)) {
+                ret.add(data.get(i));
+            }
+        }
+        return ret;
+    }
+
+    public Set<Integer> getSelectedChangesetIds() {
+        Set<Integer> ret = new HashSet<Integer>();
+        for (int i=0; i < getSize(); i++) {
+            if (selectionModel.isSelectedIndex(i)) {
+                ret.add(data.get(i).getId());
+            }
+        }
+        return ret;
+    }
+
+    public void setSelectedChangesets(Collection<Changeset> changesets) {
+        selectionModel.clearSelection();
+        if (changesets == null) return;
+        for (Changeset cs: changesets) {
+            int idx = data.indexOf(cs);
+            if (idx < 0) {
+                continue;
+            }
+            selectionModel.addSelectionInterval(idx,idx);
+        }
+    }
+
+    protected void setChangesets(Collection<Changeset> changesets) {
+        Set<Changeset> sel = getSelectedChangesets();
+        data.clear();
+        if (changesets == null) {
+            fireContentsChanged(this, 0, getSize());
+            return;
+        }
+        data.addAll(changesets);
+        ChangesetCache cache = ChangesetCache.getInstance();
+        for (Changeset cs: data) {
+            if (cache.contains(cs) && cache.get(cs.getId()) != cs) {
+                cs.mergeFrom(cache.get(cs.getId()));
+            }
+        }
+        sort();
+        fireIntervalAdded(this, 0, getSize());
+        setSelectedChangesets(sel);
+    }
+
+    public void initFromChangesetIds(Collection<Integer> ids) {
+        if (ids == null || ids.isEmpty()) {
+            setChangesets(null);
+            return;
+        }
+        Set<Changeset> changesets = new HashSet<Changeset>(ids.size());
+        for (int id: ids) {
+            if (id <= 0) {
+                continue;
+            }
+            changesets.add(new Changeset(id));
+        }
+        setChangesets(changesets);
+    }
+
+    public void initFromPrimitives(Collection<? extends OsmPrimitive> primitives) {
+        if (primitives == null) {
+            setChangesets(null);
+            return;
+        }
+        Set<Changeset> changesets = new HashSet<Changeset>();
+        for (OsmPrimitive p: primitives) {
+            if (p.getChangesetId() <= 0) {
+                continue;
+            }
+            changesets.add(new Changeset(p.getChangesetId()));
+        }
+        setChangesets(changesets);
+    }
+
+    public void initFromDataSet(DataSet ds) {
+        if (ds == null) {
+            setChangesets(null);
+            return;
+        }
+        Set<Changeset> changesets = new HashSet<Changeset>();
+        for (OsmPrimitive p: ds.getNodes()) {
+            if (p.getChangesetId() <=0 ) {
+                continue;
+            }
+            changesets.add(new Changeset(p.getChangesetId()));
+        }
+        for (OsmPrimitive p: ds.getWays()) {
+            if (p.getChangesetId() <=0 ) {
+                continue;
+            }
+            changesets.add(new Changeset(p.getChangesetId()));
+        }
+        for (OsmPrimitive p: ds.getRelations()) {
+            if (p.getChangesetId() <=0 ) {
+                continue;
+            }
+            changesets.add(new Changeset(p.getChangesetId()));
+        }
+        setChangesets(changesets);
+    }
+
+    @Override
+    public Object getElementAt(int idx) {
+        return data.get(idx);
+    }
+
+    @Override
+    public int getSize() {
+        return data.size();
+    }
+
+    protected void sort() {
+        Collections.sort(
+                data,
+                new Comparator<Changeset>() {
+                    public int compare(Changeset cs1, Changeset cs2) {
+                        if (cs1.getId() > cs2.getId()) return -1;
+                        if (cs1.getId() == cs2.getId()) return 0;
+                        return 1;
+                    }
+                }
+        );
+    }
+
+    /* ---------------------------------------------------------------------------- */
+    /* Interface ChangesetCacheListener                                             */
+    /* ---------------------------------------------------------------------------- */
+    public void changesetCacheUpdated(ChangesetCacheEvent event) {
+        Set<Changeset> sel = getSelectedChangesets();
+        for(Changeset cs: event.getAddedChangesets()) {
+            int idx = data.indexOf(cs);
+            if (idx >= 0 && data.get(idx) != cs) {
+                data.get(idx).mergeFrom(cs);
+            }
+        }
+        for(Changeset cs: event.getUpdatedChangesets()) {
+            int idx = data.indexOf(cs);
+            if (idx >= 0 && data.get(idx) != cs) {
+                data.get(idx).mergeFrom(cs);
+            }
+        }
+        for(Changeset cs: event.getRemovedChangesets()) {
+            int idx = data.indexOf(cs);
+            if (idx >= 0) {
+                // replace with an incomplete changeset
+                data.set(idx, new Changeset(cs.getId()));
+            }
+        }
+        fireContentsChanged(this, 0, getSize());
+        setSelectedChangesets(sel);
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetsInActiveDataLayerListModel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetsInActiveDataLayerListModel.java	(revision 2613)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/ChangesetsInActiveDataLayerListModel.java	(revision 2613)
@@ -0,0 +1,47 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.dialogs.changeset;
+
+import javax.swing.DefaultListSelectionModel;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.layer.DataChangeListener;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.gui.layer.Layer.LayerChangeListener;
+
+public class ChangesetsInActiveDataLayerListModel extends ChangesetListModel implements LayerChangeListener, DataChangeListener{
+
+    public ChangesetsInActiveDataLayerListModel(DefaultListSelectionModel selectionModel) {
+        super(selectionModel);
+    }
+
+    /* ---------------------------------------------------------------------------- */
+    /* Interface LayerChangeListener                                                */
+    /* ---------------------------------------------------------------------------- */
+    public void activeLayerChange(Layer oldLayer, Layer newLayer) {
+        if (oldLayer != null && oldLayer instanceof OsmDataLayer) {
+            OsmDataLayer l = (OsmDataLayer)oldLayer;
+            l.listenerDataChanged.remove(this);
+        }
+        if (newLayer == null) {
+            setChangesets(null);
+        } else if (newLayer instanceof OsmDataLayer){
+            OsmDataLayer l = (OsmDataLayer)newLayer;
+            l.listenerDataChanged.add(this);
+            initFromDataSet(l.data);
+        } else {
+            setChangesets(null);
+        }
+    }
+    public void layerAdded(Layer newLayer) {}
+    public void layerRemoved(Layer oldLayer) {}
+
+    /* ---------------------------------------------------------------------------- */
+    /* Interface DataChangeListener                                                 */
+    /* ---------------------------------------------------------------------------- */
+    public void dataChanged(OsmDataLayer l) {
+        if (l == null) return;
+        if (l != Main.main.getEditLayer()) return;
+        initFromDataSet(l.data);
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/DownloadChangesetsTask.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/DownloadChangesetsTask.java	(revision 2613)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/changeset/DownloadChangesetsTask.java	(revision 2613)
@@ -0,0 +1,89 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.dialogs.changeset;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.swing.SwingUtilities;
+
+import org.openstreetmap.josm.data.osm.Changeset;
+import org.openstreetmap.josm.data.osm.ChangesetCache;
+import org.openstreetmap.josm.gui.ExceptionDialogUtil;
+import org.openstreetmap.josm.gui.PleaseWaitRunnable;
+import org.openstreetmap.josm.io.OsmServerChangesetReader;
+import org.openstreetmap.josm.io.OsmTransferException;
+import org.xml.sax.SAXException;
+
+public class DownloadChangesetsTask extends PleaseWaitRunnable{
+
+    private Set<Integer> idsToDownload;
+    private OsmServerChangesetReader reader;
+    private boolean cancelled;
+    private Exception lastException;
+    private List<Changeset> downloadedChangesets;
+
+    public DownloadChangesetsTask(Collection<Integer> ids) {
+        super(tr("Download changesets"));
+        idsToDownload = new HashSet<Integer>();
+        if (ids == null ||  ids.isEmpty())
+            return;
+        for (int id: ids) {
+            if (id <= 0) {
+                continue;
+            }
+            idsToDownload.add(id);
+        }
+    }
+
+    @Override
+    protected void cancel() {
+        cancelled = true;
+        synchronized (this) {
+            if (reader != null) {
+                reader.cancel();
+            }
+        }
+    }
+
+    @Override
+    protected void finish() {
+        if (cancelled)
+            return;
+        if (lastException != null) {
+            ExceptionDialogUtil.explainException(lastException);
+        }
+        Runnable r = new Runnable() {
+            public void run() {
+                ChangesetCache.getInstance().update(downloadedChangesets);
+            }
+        };
+
+        if (SwingUtilities.isEventDispatchThread()) {
+            r.run();
+        } else {
+            SwingUtilities.invokeLater(r);
+        }
+    }
+
+    @Override
+    protected void realRun() throws SAXException, IOException, OsmTransferException {
+        try {
+            synchronized (this) {
+                reader = new OsmServerChangesetReader();
+            }
+            downloadedChangesets = reader.readChangesets(idsToDownload, getProgressMonitor().createSubTaskMonitor(0, false));
+        } catch(Exception e) {
+            if (cancelled)
+                // ignore exception if cancelled
+                return;
+            if (e instanceof RuntimeException)
+                throw (RuntimeException)e;
+            lastException = e;
+        }
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/io/ChangesetManagementPanel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/io/ChangesetManagementPanel.java	(revision 2612)
+++ trunk/src/org/openstreetmap/josm/gui/io/ChangesetManagementPanel.java	(revision 2613)
@@ -26,4 +26,5 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.osm.Changeset;
+import org.openstreetmap.josm.data.osm.ChangesetCache;
 import org.openstreetmap.josm.gui.JMultilineLabel;
 import org.openstreetmap.josm.tools.ImageProvider;
@@ -104,4 +105,5 @@
         gc.weightx = 1.0;
         model = new OpenChangesetComboBoxModel();
+        ChangesetCache.getInstance().addChangesetCacheListener(model);
         cbOpenChangesets = new JComboBox(model);
         cbOpenChangesets.setToolTipText("Select an open changeset");
@@ -171,4 +173,12 @@
     }
 
+    public void setSelectedChangesetForNextUpload(Changeset cs) {
+        int idx  = model.getIndexOf(cs);
+        if (idx >=0) {
+            rbExisting.setSelected(true);
+            model.setSelectedItem(cs);
+        }
+    }
+
     /**
      * Replies the currently selected changeset. null, if no changeset is
@@ -203,32 +213,4 @@
     }
 
-    public void updateListOfChangesetsAfterUploadOperation(Changeset cs) {
-        if (cs == null || cs.isNew()) {
-            model.setSelectedItem(null);
-        } else if (cs.isOpen()){
-            if (cs.get("created_by") == null) {
-                cs.put("created_by", getDefaultCreatedBy());
-            }
-            model.addOrUpdate(cs);
-            cs = model.getChangesetById(cs.getId());
-            model.setSelectedItem(cs);
-            rbExisting.setSelected(true);
-        } else if (!cs.isOpen()){
-            removeChangeset(cs);
-            rbUseNew.setSelected(true);
-        }
-    }
-
-    /**
-     * Remove a changeset from the list of open changeset
-     *
-     * @param cs the changeset to be removed. Ignored if null.
-     */
-    public void removeChangeset(Changeset cs) {
-        if (cs ==  null) return;
-        model.removeChangeset(cs);
-        refreshGUI();
-    }
-
     /* ---------------------------------------------------------------------------- */
     /* Interface ListDataListener                                                   */
@@ -256,4 +238,7 @@
             if (rbExisting.isSelected()) {
                 firePropertyChange(SELECTED_CHANGESET_PROP, null, cs);
+                if (cs == null) {
+                    rbUseNew.setSelected(true);
+                }
             }
         }
Index: trunk/src/org/openstreetmap/josm/gui/io/CloseChangesetDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/io/CloseChangesetDialog.java	(revision 2612)
+++ trunk/src/org/openstreetmap/josm/gui/io/CloseChangesetDialog.java	(revision 2613)
@@ -1,4 +1,6 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.gui.io;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
 
 import java.awt.BorderLayout;
@@ -6,4 +8,7 @@
 import java.awt.FlowLayout;
 import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -12,4 +17,5 @@
 import javax.swing.BorderFactory;
 import javax.swing.DefaultListModel;
+import javax.swing.JComponent;
 import javax.swing.JDialog;
 import javax.swing.JLabel;
@@ -18,4 +24,5 @@
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
+import javax.swing.KeyStroke;
 import javax.swing.event.ListSelectionEvent;
 import javax.swing.event.ListSelectionListener;
@@ -26,6 +33,4 @@
 import org.openstreetmap.josm.tools.ImageProvider;
 import org.openstreetmap.josm.tools.WindowGeometry;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
 
 /**
@@ -41,4 +46,6 @@
     /** the list model */
     private DefaultListModel model;
+
+    private SideButton btnCloseChangesets;
 
     protected JPanel buildTopPanel() {
@@ -66,6 +73,13 @@
         CloseAction closeAction = new CloseAction();
         lstOpenChangesets.addListSelectionListener(closeAction);
-        pnl.add(new SideButton(closeAction));
-        pnl.add(new SideButton(new CancelAction()));
+        pnl.add(btnCloseChangesets = new SideButton(closeAction));
+        btnCloseChangesets.setFocusable(true);
+        btnCloseChangesets.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0), "enter");
+        btnCloseChangesets.getActionMap().put("enter",closeAction);
+
+        // -- cancel action
+        SideButton btn;
+        pnl.add(btn = new SideButton(new CancelAction()));
+        btn.setFocusable(true);
         return pnl;
     }
@@ -77,4 +91,8 @@
         getContentPane().add(buildCenterPanel(), BorderLayout.CENTER);
         getContentPane().add(buildSouthPanel(), BorderLayout.SOUTH);
+
+        getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE,0), "escape");
+        getRootPane().getActionMap().put("escape", new CancelAction());
+        addWindowListener(new WindowEventHandler());
     }
 
@@ -127,8 +145,26 @@
         }
 
-        public void actionPerformed(ActionEvent e) {
+        public void cancel() {
             setCanceled(true);
             setVisible(false);
         }
+
+        public void actionPerformed(ActionEvent e) {
+            cancel();
+        }
+    }
+
+    class WindowEventHandler extends WindowAdapter {
+
+        @Override
+        public void windowActivated(WindowEvent arg0) {
+            btnCloseChangesets.requestFocusInWindow();
+        }
+
+        @Override
+        public void windowClosing(WindowEvent arg0) {
+            new CancelAction().cancel();
+        }
+
     }
 
@@ -162,4 +198,7 @@
         for (Changeset cs: changesets) {
             model.addElement(cs);
+        }
+        if (!changesets.isEmpty()) {
+            lstOpenChangesets.getSelectionModel().setSelectionInterval(0, changesets.size()-1);
         }
     }
Index: trunk/src/org/openstreetmap/josm/gui/io/CloseChangesetTask.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/io/CloseChangesetTask.java	(revision 2612)
+++ trunk/src/org/openstreetmap/josm/gui/io/CloseChangesetTask.java	(revision 2613)
@@ -11,4 +11,5 @@
 
 import org.openstreetmap.josm.data.osm.Changeset;
+import org.openstreetmap.josm.data.osm.ChangesetCache;
 import org.openstreetmap.josm.gui.ExceptionDialogUtil;
 import org.openstreetmap.josm.gui.PleaseWaitRunnable;
@@ -59,7 +60,5 @@
                 new Runnable() {
                     public void run() {
-                        for (Changeset cs: closedChangesets) {
-                            UploadDialog.getUploadDialog().updateListOfChangesetsAfterUploadOperation(cs);
-                        }
+                        ChangesetCache.getInstance().update(closedChangesets);
                     }
                 }
Index: trunk/src/org/openstreetmap/josm/gui/io/DownloadOpenChangesetsTask.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/io/DownloadOpenChangesetsTask.java	(revision 2612)
+++ trunk/src/org/openstreetmap/josm/gui/io/DownloadOpenChangesetsTask.java	(revision 2613)
@@ -12,4 +12,5 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.osm.Changeset;
+import org.openstreetmap.josm.data.osm.ChangesetCache;
 import org.openstreetmap.josm.data.osm.UserInfo;
 import org.openstreetmap.josm.gui.ExceptionDialogUtil;
@@ -70,5 +71,5 @@
                 new Runnable() {
                     public void run() {
-                        model.setChangesets(changesets);
+                        ChangesetCache.getInstance().update(changesets);
                     }
                 }
Index: trunk/src/org/openstreetmap/josm/gui/io/OpenChangesetComboBoxModel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/io/OpenChangesetComboBoxModel.java	(revision 2612)
+++ trunk/src/org/openstreetmap/josm/gui/io/OpenChangesetComboBoxModel.java	(revision 2613)
@@ -2,8 +2,5 @@
 package org.openstreetmap.josm.gui.io;
 
-import static org.openstreetmap.josm.tools.I18n.tr;
-
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.List;
 
@@ -11,4 +8,7 @@
 
 import org.openstreetmap.josm.data.osm.Changeset;
+import org.openstreetmap.josm.data.osm.ChangesetCache;
+import org.openstreetmap.josm.data.osm.ChangesetCacheEvent;
+import org.openstreetmap.josm.data.osm.ChangesetCacheListener;
 
 /**
@@ -16,5 +16,5 @@
  *
  */
-public class OpenChangesetComboBoxModel extends DefaultComboBoxModel {
+public class OpenChangesetComboBoxModel extends DefaultComboBoxModel implements ChangesetCacheListener {
     private List<Changeset> changesets;
     private long uid;
@@ -32,48 +32,13 @@
     }
 
-    protected void internalAddOrUpdate(Changeset cs) {
-        Changeset other = getChangesetById(cs.getId());
-        if (other != null) {
-            cs.cloneFrom(other);
+    public void refresh() {
+        changesets.clear();
+        changesets.addAll(ChangesetCache.getInstance().getOpenChangesets());
+        fireContentsChanged(this, 0, getSize());
+        int idx = changesets.indexOf(selectedChangeset);
+        if (idx < 0) {
+            setSelectedItem(null);
         } else {
-            changesets.add(cs);
-        }
-    }
-
-    public void addOrUpdate(Changeset cs) {
-        if (cs.getId() <= 0 )
-            throw new IllegalArgumentException(tr("Changeset ID > 0 expected. Got {0}.", cs.getId()));
-        internalAddOrUpdate(cs);
-        fireContentsChanged(this, 0, getSize());
-    }
-
-    public void remove(long id) {
-        Changeset cs = getChangesetById(id);
-        if (cs != null) {
-            changesets.remove(cs);
-        }
-        fireContentsChanged(this, 0, getSize());
-    }
-
-    public void setChangesets(Collection<Changeset> changesets) {
-        this.changesets.clear();
-        if (changesets != null) {
-            for (Changeset cs: changesets) {
-                internalAddOrUpdate(cs);
-            }
-        }
-        fireContentsChanged(this, 0, getSize());
-        if (getSelectedItem() == null && !this.changesets.isEmpty()) {
-            setSelectedItem(this.changesets.get(0));
-        } else if (getSelectedItem() != null) {
-            if (changesets.contains(getSelectedItem())) {
-                setSelectedItem(getSelectedItem());
-            } else if (!this.changesets.isEmpty()){
-                setSelectedItem(this.changesets.get(0));
-            } else {
-                setSelectedItem(null);
-            }
-        } else {
-            setSelectedItem(null);
+            setSelectedItem(changesets.get(idx));
         }
     }
@@ -95,12 +60,11 @@
     }
 
-    public void removeChangeset(Changeset cs) {
-        if (cs == null) return;
-        changesets.remove(cs);
-        if (selectedChangeset == cs) {
-            selectFirstChangeset();
-        }
-        fireContentsChanged(this, 0, getSize());
+    /* ------------------------------------------------------------------------------------ */
+    /* ChangesetCacheListener                                                               */
+    /* ------------------------------------------------------------------------------------ */
+    public void changesetCacheUpdated(ChangesetCacheEvent event) {
+        refresh();
     }
+
     /* ------------------------------------------------------------------------------------ */
     /* ComboBoxModel                                                                        */
Index: trunk/src/org/openstreetmap/josm/gui/io/UploadDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/io/UploadDialog.java	(revision 2612)
+++ trunk/src/org/openstreetmap/josm/gui/io/UploadDialog.java	(revision 2613)
@@ -289,4 +289,8 @@
     }
 
+    public void setSelectedChangesetForNextUpload(Changeset cs) {
+        pnlChangesetManagement.setSelectedChangesetForNextUpload(cs);
+    }
+
     /**
      * Replies the {@see UploadStrategySpecification} the user entered in the dialog.
@@ -298,29 +302,4 @@
         spec.setCloseChangesetAfterUpload(pnlChangesetManagement.isCloseChangesetAfterUpload());
         return spec;
-    }
-
-    /**
-     * Sets or updates the changeset cs.
-     * If cs is null, does nothing.
-     * If cs.getId() == 0 does nothing.
-     * If cs.getId() > 0 and cs is open, adds it to the list of open
-     * changesets. If it is closed, removes it from the list of open
-     * changesets.
-     *
-     * @param cs the changeset
-     */
-    public void updateListOfChangesetsAfterUploadOperation(Changeset cs) {
-        pnlChangesetManagement.updateListOfChangesetsAfterUploadOperation(cs);
-    }
-
-    /**
-     * Removes <code>cs</code> from the list of open changesets in the upload
-     * dialog
-     *
-     * @param cs the changeset. Ignored if null.
-     */
-    public void removeChangeset(Changeset cs) {
-        if (cs == null) return;
-        pnlChangesetManagement.removeChangeset(cs);
     }
 
Index: trunk/src/org/openstreetmap/josm/gui/io/UploadPrimitivesTask.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/io/UploadPrimitivesTask.java	(revision 2612)
+++ trunk/src/org/openstreetmap/josm/gui/io/UploadPrimitivesTask.java	(revision 2613)
@@ -18,4 +18,5 @@
 import org.openstreetmap.josm.data.APIDataSet;
 import org.openstreetmap.josm.data.osm.Changeset;
+import org.openstreetmap.josm.data.osm.ChangesetCache;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.gui.DefaultNameFormatter;
@@ -139,5 +140,5 @@
         // make sure the current changeset is removed from the upload dialog.
         //
-        UploadDialog.getUploadDialog().removeChangeset(changeset);
+        ChangesetCache.getInstance().update(changeset);
         Changeset newChangeSet = new Changeset();
         newChangeSet.setKeys(this.changeset.getKeys());
@@ -211,12 +212,5 @@
                 layer.fireDataChange();
                 layer.onPostUploadToServer();
-
-                // make sure the upload dialog lists all known open changesets
-                //
-                if (lastException != null && lastException instanceof ChangesetClosedException) {
-                    UploadDialog.getUploadDialog().removeChangeset(changeset);
-                } else {
-                    UploadDialog.getUploadDialog().updateListOfChangesetsAfterUploadOperation(changeset);
-                }
+                ChangesetCache.getInstance().update(changeset);
             }
         };
@@ -298,6 +292,4 @@
         if (uploadCancelled)
             return;
-        if (lastException == null)
-            return;
 
         // depending on the success of the upload operation and on the policy for
@@ -309,4 +301,13 @@
         Runnable r = new Runnable() {
             public void run() {
+                // if the changeset is still open after this upload we want it to
+                // be selected on the next upload
+                //
+                ChangesetCache.getInstance().update(changeset);
+                if (changeset != null && changeset.isOpen()) {
+                    UploadDialog.getUploadDialog().setSelectedChangesetForNextUpload(changeset);
+                }
+                if (lastException == null)
+                    return;
                 if (lastException instanceof ChangesetClosedException) {
                     ChangesetClosedException e = (ChangesetClosedException)lastException;
@@ -337,5 +338,9 @@
             }
         };
-        SwingUtilities.invokeLater(r);
+        if (SwingUtilities.isEventDispatchThread()) {
+            r.run();
+        } else {
+            SwingUtilities.invokeLater(r);
+        }
     }
 
Index: trunk/src/org/openstreetmap/josm/io/OsmServerChangesetReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/OsmServerChangesetReader.java	(revision 2612)
+++ trunk/src/org/openstreetmap/josm/io/OsmServerChangesetReader.java	(revision 2613)
@@ -2,5 +2,12 @@
 package org.openstreetmap.josm.io;
 
+import static org.openstreetmap.josm.tools.I18n.tr;
+import static org.openstreetmap.josm.tools.I18n.trn;
+
 import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
 
@@ -9,5 +16,4 @@
 import org.openstreetmap.josm.gui.progress.NullProgressMonitor;
 import org.openstreetmap.josm.gui.progress.ProgressMonitor;
-import static org.openstreetmap.josm.tools.I18n.tr;
 
 /**
@@ -68,5 +74,5 @@
 
     /**
-     * Reads teh changeset with id <code>id</code> from the server
+     * Reads the changeset with id <code>id</code> from the server
      *
      * @param id  the changeset id. id > 0 required.
@@ -104,4 +110,53 @@
 
     /**
+     * Reads the changeset with id <code>id</code> from the server
+     *
+     * @param ids  the list of ids. Ignored if null. Only load changesets for ids > 0.
+     * @param monitor the progress monitor. Set to {@see NullProgressMonitor#INSTANCE} if null
+     * @return the changeset read
+     * @throws OsmTransferException thrown if something goes wrong
+     * @throws IllegalArgumentException if id <= 0
+     */
+    public List<Changeset> readChangesets(Collection<Integer> ids, ProgressMonitor monitor) throws OsmTransferException {
+        if (ids == null)
+            return Collections.emptyList();
+        if (monitor == null) {
+            monitor = NullProgressMonitor.INSTANCE;
+        }
+        try {
+            monitor.beginTask(trn("Downloading {0} changeset ...", "Downloading {0} changesets ...",ids.size(),ids.size()));
+            monitor.setTicksCount(ids.size());
+            List<Changeset> ret = new ArrayList<Changeset>();
+            int i=0;
+            for (Iterator<Integer> it = ids.iterator(); it.hasNext(); ) {
+                int id = it.next();
+                if (id <= 0) {
+                    continue;
+                }
+                i++;
+                StringBuffer sb = new StringBuffer();
+                sb.append("changeset/").append(id);
+                InputStream in = getInputStream(sb.toString(), monitor.createSubTaskMonitor(1, true));
+                if (in == null)
+                    return null;
+                monitor.indeterminateSubTask(tr("({0}/{1}) Downloading changeset {0} ...", i,ids.size(), id));
+                List<Changeset> changesets = OsmChangesetParser.parse(in, monitor.createSubTaskMonitor(1, true));
+                if (changesets == null || changesets.isEmpty()) {
+                    continue;
+                }
+                ret.addAll(changesets);
+                monitor.worked(1);
+            }
+            return ret;
+        } catch(OsmTransferException e) {
+            throw e;
+        } catch(IllegalDataException e) {
+            throw new OsmTransferException(e);
+        } finally {
+            monitor.finishTask();
+        }
+    }
+
+    /**
      * not implemented yet
      *
