Index: trunk/src/org/openstreetmap/josm/gui/history/HistoryBrowserDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/history/HistoryBrowserDialog.java	(revision 2017)
+++ trunk/src/org/openstreetmap/josm/gui/history/HistoryBrowserDialog.java	(revision 2019)
@@ -8,7 +8,8 @@
 import java.awt.FlowLayout;
 import java.awt.event.ActionEvent;
+import java.awt.event.WindowAdapter;
+import java.awt.event.WindowEvent;
 
 import javax.swing.AbstractAction;
-import javax.swing.JButton;
 import javax.swing.JDialog;
 import javax.swing.JOptionPane;
@@ -17,5 +18,9 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.osm.history.History;
+import org.openstreetmap.josm.data.osm.history.HistoryDataSet;
+import org.openstreetmap.josm.data.osm.history.HistoryDataSetListener;
+import org.openstreetmap.josm.gui.SideButton;
 import org.openstreetmap.josm.gui.dialogs.HistoryDialog;
+import org.openstreetmap.josm.tools.ImageProvider;
 
 /**
@@ -24,5 +29,5 @@
  * 
  */
-public class HistoryBrowserDialog extends JDialog {
+public class HistoryBrowserDialog extends JDialog implements HistoryDataSetListener{
 
     /** the embedded browser */
@@ -37,7 +42,7 @@
         String title = "";
         switch(h.getEarliest().getType()) {
-        case NODE:  title = marktr("History for node {0}"); break;
-        case WAY: title = marktr("History for way {0}"); break;
-        case RELATION:  title = marktr("History for relation {0}"); break;
+            case NODE:  title = marktr("History for node {0}"); break;
+            case WAY: title = marktr("History for way {0}"); break;
+            case RELATION:  title = marktr("History for relation {0}"); break;
         }
         setTitle(tr(
@@ -57,7 +62,11 @@
 
         JPanel pnl = new JPanel();
-        pnl.setLayout(new FlowLayout(FlowLayout.RIGHT));
+        pnl.setLayout(new FlowLayout(FlowLayout.CENTER));
 
-        JButton btn = new JButton(new CloseAction());
+        SideButton btn = new SideButton(new ReloadAction());
+        btn.setName("btn.reload");
+        pnl.add(btn);
+
+        btn = new SideButton(new CloseAction());
         btn.setName("btn.close");
         pnl.add(btn);
@@ -77,4 +86,6 @@
         setHistory(history);
         renderTitle(history);
+        HistoryDataSet.getInstance().addHistoryDataSetListener(this);
+        addWindowListener(new WindowClosingAdapter());
     }
 
@@ -87,31 +98,10 @@
     }
 
-    /**
-     * registers this dialog with the registry of history dialogs
-     * 
-     * @see HistoryDialog#registerHistoryBrowserDialog(long, HistoryBrowserDialog)
-     */
-    protected void register() {
-        HistoryDialog.registerHistoryBrowserDialog(browser.getHistory().getId(), this);
-    }
-
-    /**
-     * unregisters this dialog from the registry of history dialogs
-     * 
-     * @see HistoryDialog#unregisterHistoryBrowserDialog(long)
-     */
-    protected void unregister() {
-        HistoryDialog.unregisterHistoryBrowserDialog(browser.getHistory().getId());
-    }
-
-    @Override
-    public void setVisible(boolean visible) {
-        if (visible) {
-            register();
-            toFront();
-        } else {
-            unregister();
+    public void historyUpdated(HistoryDataSet source, long primitiveId) {
+        if (primitiveId == browser.getHistory().getId()) {
+            browser.populate(source.getHistory(primitiveId));
+        } else if (primitiveId == 0) {
+            browser.populate(source.getHistory(browser.getHistory().getId()));
         }
-        super.setVisible(visible);
     }
 
@@ -120,8 +110,32 @@
             putValue(NAME, tr("Close"));
             putValue(SHORT_DESCRIPTION, tr("Close the dialog"));
+            putValue(SMALL_ICON, ImageProvider.get("ok"));
         }
 
         public void actionPerformed(ActionEvent e) {
-            setVisible(false);
+            HistoryDataSet.getInstance().removeHistoryDataSetListener(HistoryBrowserDialog.this);
+            HistoryBrowserDialogManager.getInstance().hide(HistoryBrowserDialog.this);
+        }
+    }
+
+    class ReloadAction extends AbstractAction {
+        public ReloadAction() {
+            putValue(NAME, tr("Reload"));
+            putValue(SHORT_DESCRIPTION, tr("Reload the history from the server"));
+            putValue(SMALL_ICON, ImageProvider.get("dialogs", "refresh"));
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            HistoryLoadTask task = new HistoryLoadTask();
+            task.add(browser.getHistory());
+            Main.worker.submit(task);
+        }
+    }
+
+    class WindowClosingAdapter extends WindowAdapter {
+        @Override
+        public void windowClosing(WindowEvent e) {
+            HistoryDataSet.getInstance().removeHistoryDataSetListener(HistoryBrowserDialog.this);
+            HistoryBrowserDialogManager.getInstance().hide(HistoryBrowserDialog.this);
         }
     }
Index: trunk/src/org/openstreetmap/josm/gui/history/HistoryBrowserDialogManager.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/history/HistoryBrowserDialogManager.java	(revision 2019)
+++ trunk/src/org/openstreetmap/josm/gui/history/HistoryBrowserDialogManager.java	(revision 2019)
@@ -0,0 +1,81 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.history;
+
+import java.awt.Dimension;
+import java.awt.Point;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.openstreetmap.josm.tools.WindowGeometry;
+
+public class HistoryBrowserDialogManager {
+    static private HistoryBrowserDialogManager instance;
+    static public HistoryBrowserDialogManager getInstance() {
+        if (instance == null) {
+            instance = new HistoryBrowserDialogManager();
+        }
+        return instance;
+    }
+
+    private Map<Long, HistoryBrowserDialog> dialogs;
+
+    protected HistoryBrowserDialogManager() {
+        dialogs = new HashMap<Long, HistoryBrowserDialog>();
+    }
+
+    public boolean existsDialog(long id) {
+        return dialogs.containsKey(id);
+    }
+
+    public void show(long id, HistoryBrowserDialog dialog) {
+        if (dialogs.values().contains(dialog)) {
+            show(id);
+        } else {
+            placeOnScreen(dialog);
+            dialog.setVisible(true);
+            dialogs.put(id, dialog);
+        }
+    }
+
+    public void show(long id) {
+        if (dialogs.keySet().contains(id)) {
+            dialogs.get(id).toFront();
+        }
+    }
+
+    protected boolean hasDialogWithCloseUpperLeftCorner(Point p) {
+        for (HistoryBrowserDialog dialog: dialogs.values()) {
+            Point corner = dialog.getLocation();
+            if (p.x >= corner.x -5 && corner.x + 5 >= p.x
+                    && p.y >= corner.y -5 && corner.y + 5 >= p.y)
+                return true;
+        }
+        return false;
+    }
+
+    public void placeOnScreen(HistoryBrowserDialog dialog) {
+        WindowGeometry geometry = WindowGeometry.centerOnScreen(new Dimension(800,500));
+        geometry.apply(dialog);
+        Point p = dialog.getLocation();
+        while(hasDialogWithCloseUpperLeftCorner(p)) {
+            p.x +=20;
+            p.y += 20;
+        }
+        dialog.setLocation(p);
+    }
+
+    public void hide(HistoryBrowserDialog dialog) {
+        long id = 0;
+        for (long i: dialogs.keySet()) {
+            if (dialogs.get(i) == dialog) {
+                id = i;
+                break;
+            }
+        }
+        if (id > 0) {
+            dialogs.remove(id);
+        }
+        dialog.setVisible(false);
+        dialog.dispose();
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/history/HistoryBrowserModel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/history/HistoryBrowserModel.java	(revision 2017)
+++ trunk/src/org/openstreetmap/josm/gui/history/HistoryBrowserModel.java	(revision 2019)
@@ -103,4 +103,5 @@
         setChanged();
         notifyObservers();
+        versionTableModel.fireTableDataChanged();
     }
 
Index: trunk/src/org/openstreetmap/josm/gui/history/HistoryLoadTask.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/history/HistoryLoadTask.java	(revision 2019)
+++ trunk/src/org/openstreetmap/josm/gui/history/HistoryLoadTask.java	(revision 2019)
@@ -0,0 +1,146 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.history;
+
+import static org.openstreetmap.josm.tools.I18n.marktr;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.io.IOException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
+import org.openstreetmap.josm.data.osm.history.History;
+import org.openstreetmap.josm.data.osm.history.HistoryDataSet;
+import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive;
+import org.openstreetmap.josm.gui.ExceptionDialogUtil;
+import org.openstreetmap.josm.gui.PleaseWaitRunnable;
+import org.openstreetmap.josm.io.OsmApi;
+import org.openstreetmap.josm.io.OsmServerHistoryReader;
+import org.openstreetmap.josm.io.OsmTransferException;
+import org.xml.sax.SAXException;
+
+public class HistoryLoadTask extends PleaseWaitRunnable {
+
+    private boolean cancelled = false;
+    private Exception lastException  = null;
+    private Map<Long, OsmPrimitiveType> toLoad;
+    private HistoryDataSet loadedData;
+
+    public HistoryLoadTask() {
+        super(tr("Load history"), true);
+        toLoad = new HashMap<Long, OsmPrimitiveType>();
+    }
+
+    public HistoryLoadTask add(long id, OsmPrimitiveType type) {
+        if (id <= 0)
+            throw new IllegalArgumentException(tr("id > 0 expected, got {0}", id));
+        if (type == null)
+            throw new IllegalArgumentException(tr("parameter ''{0}'' must not be null", "type"));
+        if (!toLoad.containsKey(id)) {
+            toLoad.put(id, type);
+        }
+        return this;
+    }
+
+    public HistoryLoadTask add(HistoryOsmPrimitive primitive) {
+        if (primitive == null)
+            throw new IllegalArgumentException(tr("parameter ''{0}'' must not be null", "primitive"));
+        if (!toLoad.containsKey(primitive.getId())) {
+            toLoad.put(primitive.getId(), primitive.getType());
+        }
+        return this;
+    }
+
+    public HistoryLoadTask add(History history) {
+        if (history == null)
+            throw new IllegalArgumentException(tr("parameter ''{0}'' must not be null", "history"));
+        if (!toLoad.containsKey(history.getId())) {
+            toLoad.put(history.getId(), history.getEarliest().getType());
+        }
+        return this;
+    }
+
+    public HistoryLoadTask add(OsmPrimitive primitive) {
+        if (primitive == null)
+            throw new IllegalArgumentException(tr("parameter ''{0}'' must not be null", "primitive"));
+        return add(primitive.id, OsmPrimitiveType.from(primitive));
+    }
+
+    public HistoryLoadTask add(Collection<? extends OsmPrimitive> primitives) {
+        if (primitives == null)
+            throw new IllegalArgumentException(tr("parameter ''{0}'' must not be null", "primitives"));
+        for (OsmPrimitive primitive: primitives) {
+            if (primitive == null) {
+                continue;
+            }
+            add(primitive);
+        }
+        return this;
+    }
+
+    @Override
+    protected void cancel() {
+        OsmApi.getOsmApi().cancel();
+        cancelled = true;
+    }
+
+    @Override
+    protected void finish() {
+        if (isCancelled())
+            return;
+        if (lastException != null) {
+            ExceptionDialogUtil.explainException(lastException);
+            return;
+        }
+        HistoryDataSet.getInstance().mergeInto(loadedData);
+    }
+
+    @Override
+    protected void realRun() throws SAXException, IOException, OsmTransferException {
+        loadedData = new HistoryDataSet();
+        try {
+            for(Map.Entry<Long, OsmPrimitiveType> entry: toLoad.entrySet()) {
+                if (cancelled) {
+                    break;
+                }
+                if (entry.getKey() == 0) {
+                    continue;
+                }
+                String msg = "";
+                switch(entry.getValue()) {
+                    case NODE: msg = marktr("Loading history for node {0}"); break;
+                    case WAY: msg = marktr("Loading history for way {0}"); break;
+                    case RELATION: msg = marktr("Loading history for relation {0}"); break;
+                }
+                progressMonitor.indeterminateSubTask(tr(msg,
+                        Long.toString(entry.getKey())));
+                OsmServerHistoryReader reader = null;
+                HistoryDataSet ds = null;
+                try {
+                    reader = new OsmServerHistoryReader(entry.getValue(), entry.getKey());
+                    ds = reader.parseHistory(progressMonitor.createSubTaskMonitor(1, false));
+                } catch(OsmTransferException e) {
+                    if (cancelled)
+                        return;
+                    throw e;
+                }
+                loadedData.mergeInto(ds);
+            }
+        } catch(OsmTransferException e) {
+            lastException = e;
+            return;
+        }
+    }
+
+    public boolean isCancelled() {
+        return cancelled;
+    }
+
+    public Exception getLastException() {
+        return lastException;
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/history/VersionTable.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/history/VersionTable.java	(revision 2017)
+++ trunk/src/org/openstreetmap/josm/gui/history/VersionTable.java	(revision 2019)
@@ -56,5 +56,5 @@
         public void mouseClicked(MouseEvent e) {
             switch(e.getClickCount()) {
-            case 2: handleDoubleClick(e); break;
+                case 2: handleDoubleClick(e); break;
             }
         }
