Index: /trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 2447)
+++ /trunk/src/org/openstreetmap/josm/data/osm/OsmPrimitive.java	(revision 2448)
@@ -811,5 +811,5 @@
      * @throws IllegalArgumentException thrown if other is null.
      * @throws DataIntegrityProblemException thrown if either this is new and other is not, or other is new and this is not
-     * @throws DataIntegrityProblemException thrown if other is new and other.getId() != this.getId()
+     * @throws DataIntegrityProblemException thrown if other isn't new and other.getId() != this.getId()
      */
     public void mergeFrom(OsmPrimitive other) {
@@ -1025,4 +1025,12 @@
     public abstract void updatePosition();
 
+    /**
+     * Replies the unique primitive id for this primitive
+     * 
+     * @return the unique primitive id for this primitive
+     */
+    public PrimitiveId getPrimitiveId() {
+        return new SimplePrimitiveId(getUniqueId(), getType());
+    }
 }
 
Index: /trunk/src/org/openstreetmap/josm/data/osm/SimplePrimitiveId.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/SimplePrimitiveId.java	(revision 2447)
+++ /trunk/src/org/openstreetmap/josm/data/osm/SimplePrimitiveId.java	(revision 2448)
@@ -20,5 +20,30 @@
     }
 
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + (int) (id ^ (id >>> 32));
+        result = prime * result + ((type == null) ? 0 : type.hashCode());
+        return result;
+    }
 
-
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        SimplePrimitiveId other = (SimplePrimitiveId) obj;
+        if (id != other.id)
+            return false;
+        if (type == null) {
+            if (other.type != null)
+                return false;
+        } else if (!type.equals(other.type))
+            return false;
+        return true;
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/data/osm/history/History.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/history/History.java	(revision 2447)
+++ /trunk/src/org/openstreetmap/josm/data/osm/history/History.java	(revision 2448)
@@ -9,8 +9,14 @@
 import java.util.Date;
 import java.util.List;
-import java.util.NoSuchElementException;
 
 import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
-
+import org.openstreetmap.josm.data.osm.PrimitiveId;
+import org.openstreetmap.josm.data.osm.SimplePrimitiveId;
+
+/**
+ * Represents the history of an OSM primitive. The history consists
+ * of a list of object snapshots with a specific version.
+ * 
+ */
 public class History{
     private static interface FilterPredicate {
@@ -25,14 +31,34 @@
             }
         }
-        return new History(history.id, out);
-    }
-
+        return new History(history.id, history.type,out);
+    }
+
+    /** the list of object snapshots */
     private ArrayList<HistoryOsmPrimitive> versions;
-    long id;
-
-    protected History(long id, List<HistoryOsmPrimitive> versions) {
+    /** the object id */
+    private long id;
+    private OsmPrimitiveType type;
+
+    /**
+     * Creates a new history for an OSM primitive
+     * 
+     * @param id the id. >0 required.
+     * @param type the primitive type. Must not be null.
+     * @param versions a list of versions. Can be null.
+     * @throws IllegalArgumentException thrown if id <= 0
+     * @throws IllegalArgumentException if type is null
+     * 
+     */
+    protected History(long id, OsmPrimitiveType type, List<HistoryOsmPrimitive> versions) {
+        if (id <= 0)
+            throw new IllegalArgumentException(tr("Parameter ''{0}'' > 0 expected, got {1}", "id", id));
+        if (type == null)
+            throw new IllegalArgumentException(tr("Parameter ''{0}'' must not be null", "type"));
         this.id = id;
+        this.type = type;
         this.versions = new ArrayList<HistoryOsmPrimitive>();
-        this.versions.addAll(versions);
+        if (versions != null) {
+            this.versions.addAll(versions);
+        }
     }
 
@@ -47,5 +73,5 @@
                 }
         );
-        return new History(id, copy);
+        return new History(id, type, copy);
     }
 
@@ -60,5 +86,5 @@
                 }
         );
-        return new History(id, copy);
+        return new History(id, type,copy);
     }
 
@@ -139,4 +165,13 @@
     public long getId() {
         return id;
+    }
+
+    /**
+     * Replies the primitive id for this history.
+     * 
+     * @return the primitive id
+     */
+    public PrimitiveId getPrimitmiveId() {
+        return new SimplePrimitiveId(id, type);
     }
 
@@ -149,4 +184,11 @@
     }
 
+    /**
+     * Replies the history primitive with version <code>version</code>. null,
+     * if no such primitive exists.
+     * 
+     * @param version the version
+     * @return the history primitive with version <code>version</code>
+     */
     public HistoryOsmPrimitive getByVersion(long version) {
         for (HistoryOsmPrimitive primitive: versions) {
@@ -154,20 +196,20 @@
                 return primitive;
         }
-        throw new NoSuchElementException(tr("There's no primitive with version {0} in this history.", version));
+        return null;
     }
 
     public HistoryOsmPrimitive getByDate(Date date) {
-        sortAscending();
-
-        if (versions.isEmpty())
-            throw new NoSuchElementException(tr("There's no version valid at date ''{0}'' in this history.", date));
-        if (get(0).getTimestamp().compareTo(date)> 0)
-            throw new NoSuchElementException(tr("There's no version valid at date ''{0}'' in this history.", date));
-        for (int i = 1; i < versions.size();i++) {
-            if (get(i-1).getTimestamp().compareTo(date) <= 0
-                    && get(i).getTimestamp().compareTo(date) >= 0)
-                return get(i);
-        }
-        return getLatest();
+        History h = sortAscending();
+
+        if (h.versions.isEmpty())
+            return null;
+        if (h.get(0).getTimestamp().compareTo(date)> 0)
+            return null;
+        for (int i = 1; i < h.versions.size();i++) {
+            if (h.get(i-1).getTimestamp().compareTo(date) <= 0
+                    && h.get(i).getTimestamp().compareTo(date) >= 0)
+                return h.get(i);
+        }
+        return h.getLatest();
     }
 
@@ -180,5 +222,5 @@
     public HistoryOsmPrimitive getEarliest() {
         if (isEmpty())
-            throw new NoSuchElementException(tr("No earliest version found. History is empty."));
+            return null;
         return sortAscending().versions.get(0);
     }
@@ -186,5 +228,5 @@
     public HistoryOsmPrimitive getLatest() {
         if (isEmpty())
-            throw new NoSuchElementException(tr("No latest version found. History is empty."));
+            return null;
         return sortDescending().versions.get(0);
     }
@@ -199,7 +241,5 @@
 
     public OsmPrimitiveType getType() {
-        if (isEmpty())
-            throw new NoSuchElementException(tr("No type found. History is empty."));
-        return versions.get(0).getType();
+        return type;
     }
 }
Index: /trunk/src/org/openstreetmap/josm/data/osm/history/HistoryDataSet.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/history/HistoryDataSet.java	(revision 2447)
+++ /trunk/src/org/openstreetmap/josm/data/osm/history/HistoryDataSet.java	(revision 2448)
@@ -6,6 +6,10 @@
 import java.util.ArrayList;
 import java.util.HashMap;
-import java.util.NoSuchElementException;
 import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.logging.Logger;
+
+import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
+import org.openstreetmap.josm.data.osm.PrimitiveId;
+import org.openstreetmap.josm.data.osm.SimplePrimitiveId;
 
 /**
@@ -15,4 +19,5 @@
  */
 public class HistoryDataSet {
+    private final static Logger logger = Logger.getLogger(HistoryDataSet.class.getName());
 
     /** the unique instance */
@@ -32,9 +37,9 @@
 
     /** the history data */
-    private HashMap<Long, ArrayList<HistoryOsmPrimitive>> data;
+    private HashMap<PrimitiveId, ArrayList<HistoryOsmPrimitive>> data;
     private CopyOnWriteArrayList<HistoryDataSetListener> listeners;
 
     public HistoryDataSet() {
-        data = new HashMap<Long, ArrayList<HistoryOsmPrimitive>>();
+        data = new HashMap<PrimitiveId, ArrayList<HistoryOsmPrimitive>>();
         listeners = new CopyOnWriteArrayList<HistoryDataSetListener>();
     }
@@ -56,5 +61,5 @@
     }
 
-    protected void fireHistoryUpdated(long id) {
+    protected void fireHistoryUpdated(SimplePrimitiveId id) {
         for (HistoryDataSetListener l : listeners) {
             l.historyUpdated(this, id);
@@ -64,23 +69,29 @@
     /**
      * Replies the history primitive for the primitive with id <code>id</code>
-     * and version <code>version</code>
+     * and version <code>version</code>. null, if no such primitive exists.
      * 
-     * @param id the id of the primitive
-     * @param version the version of the primitive
-     * @return the history primitive for the primitive with id <code>id</code>
-     * and version <code>version</code>
-     * @throws NoSuchElementException thrown if this dataset doesn't include the respective
-     * history primitive
+     * @param id the id of the primitive. > 0 required.
+     * @param type the primitive type. Must not be null.
+     * @param version the version of the primitive. > 0 required
+     * @return the history primitive for the primitive with id <code>id</code>,
+     * type <code>type</code>, and version <code>version</code>
      */
-    public HistoryOsmPrimitive get(long id, long version) throws NoSuchElementException{
-        ArrayList<HistoryOsmPrimitive> versions = data.get(id);
+    public HistoryOsmPrimitive get(long id, OsmPrimitiveType type, long version){
+        if (id <= 0)
+            throw new IllegalArgumentException(tr("Parameter ''{0}'' > 0 expected, got {1}", "id", id));
+        if (type == null)
+            throw new IllegalArgumentException(tr("Parameter ''{0}'' must not be null", "type"));
+        if (version <= 0)
+            throw new IllegalArgumentException(tr("Parameter ''{0}'' > 0 expected, got {1}", "version", version));
+
+        SimplePrimitiveId pid = new SimplePrimitiveId(id, type);
+        ArrayList<HistoryOsmPrimitive> versions = data.get(pid);
         if (versions == null)
-            throw new NoSuchElementException(tr("Didn't find an primitive with id {0} in this dataset", id));
-
+            return null;
         for (HistoryOsmPrimitive primitive: versions) {
             if (primitive.matches(id, version))
                 return primitive;
         }
-        throw new NoSuchElementException(tr("Didn't find an primitive with id {0} and version {1} in this dataset", id, version));
+        return null;
     }
 
@@ -91,22 +102,48 @@
      */
     public void put(HistoryOsmPrimitive primitive) {
-        if (data.get(primitive.getId()) == null) {
-            data.put(primitive.getId(), new ArrayList<HistoryOsmPrimitive>());
+        SimplePrimitiveId id = new SimplePrimitiveId(primitive.getId(), primitive.getType());
+        if (data.get(id) == null) {
+            data.put(id, new ArrayList<HistoryOsmPrimitive>());
         }
-        data.get(primitive.getId()).add(primitive);
-        fireHistoryUpdated(primitive.getId());
+        data.get(id).add(primitive);
+        fireHistoryUpdated(id);
     }
 
     /**
      * Replies the history for a given primitive with id <code>id</code>
+     * and type <code>type</code>.
      * 
-     * @param id the id
-     * @return the history
+     * @param id the id the if of the primitive. > 0 required
+     * @param type the type of the primitive. Must not be null.
+     * @return the history. null, if there isn't a history for <code>id</code> and
+     * <code>type</code>.
+     * @throws IllegalArgumentException thrown if id <= 0
+     * @throws IllegalArgumentException thrown if type is null
      */
-    public History getHistory(long id) {
-        ArrayList<HistoryOsmPrimitive> versions = data.get(id);
+    public History getHistory(long id, OsmPrimitiveType type) throws IllegalArgumentException{
+        if (id <= 0)
+            throw new IllegalArgumentException(tr("Parameter ''{0}'' > 0 expected, got {1}", "id", id));
+        if (type == null)
+            throw new IllegalArgumentException(tr("Parameter ''{0}'' must not be null", "type"));
+        SimplePrimitiveId pid = new SimplePrimitiveId(id, type);
+        return getHistory(pid);
+    }
+
+    /**
+     * Replies the history for a primitive with id <code>id</code>. null, if no
+     * such history exists.
+     * 
+     * @param pid the primitive id. Must not be null.
+     * @return the history for a primitive with id <code>id</code>. null, if no
+     * such history exists
+     * @throws IllegalArgumentException thrown if pid is null
+     */
+    public History getHistory(PrimitiveId pid) throws IllegalArgumentException{
+        if (pid == null)
+            throw new IllegalArgumentException(tr("Parameter ''{0}'' must not be null", "pid"));
+        ArrayList<HistoryOsmPrimitive> versions = data.get(pid);
         if (versions == null)
             return null;
-        return new History(id, versions);
+        return new History(pid.getUniqueId(), pid.getType(), versions);
     }
 
@@ -119,8 +156,8 @@
         if (other == null)
             return;
-        for (Long id : other.data.keySet()) {
+        for (PrimitiveId id : other.data.keySet()) {
             this.data.put(id, other.data.get(id));
         }
-        fireHistoryUpdated(0);
+        fireHistoryUpdated(null);
     }
 }
Index: /trunk/src/org/openstreetmap/josm/data/osm/history/HistoryDataSetListener.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/history/HistoryDataSetListener.java	(revision 2447)
+++ /trunk/src/org/openstreetmap/josm/data/osm/history/HistoryDataSetListener.java	(revision 2448)
@@ -2,5 +2,7 @@
 package org.openstreetmap.josm.data.osm.history;
 
+import org.openstreetmap.josm.data.osm.PrimitiveId;
+
 public interface HistoryDataSetListener {
-    void historyUpdated(HistoryDataSet source, long primitiveId);
+    void historyUpdated(HistoryDataSet source, PrimitiveId id);
 }
Index: /trunk/src/org/openstreetmap/josm/data/osm/history/HistoryOsmPrimitive.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/data/osm/history/HistoryOsmPrimitive.java	(revision 2447)
+++ /trunk/src/org/openstreetmap/josm/data/osm/history/HistoryOsmPrimitive.java	(revision 2448)
@@ -10,4 +10,6 @@
 
 import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
+import org.openstreetmap.josm.data.osm.PrimitiveId;
+import org.openstreetmap.josm.data.osm.SimplePrimitiveId;
 
 /**
@@ -45,5 +47,5 @@
      * @param user  the user (! null required)
      * @param uid the user id (> 0 required)
-     * @param changesetId the changeset id (> 0 required)
+     * @param changesetId the changeset id (may be null if the changeset isn't known)
      * @param timestamp the timestamp (! null required)
      *
@@ -53,7 +55,7 @@
         ensurePositiveLong(id, "id");
         ensurePositiveLong(version, "version");
-        if(uid != -1) /* allow -1 for anonymous users */
+        if(uid != -1) {
             ensurePositiveLong(uid, "uid");
-        ensurePositiveLong(changesetId, "changesetId");
+        }
         ensureNotNull(user, "user");
         ensureNotNull(timestamp, "timestamp");
@@ -63,4 +65,6 @@
         this.user = user;
         this.uid = uid;
+        // FIXME: restrict to IDs > 0 as soon as OsmPrimitive holds the
+        // changeset id too
         this.changesetId  = changesetId;
         this.timestamp = timestamp;
@@ -71,4 +75,9 @@
         return id;
     }
+
+    public PrimitiveId getPrimitiveId() {
+        return new SimplePrimitiveId(id, getType());
+    }
+
     public boolean isVisible() {
         return visible;
@@ -103,5 +112,5 @@
     public int compareTo(HistoryOsmPrimitive o) {
         if (this.id != o.id)
-            throw new ClassCastException(tr("Can't compare primitive with ID ''{0}'' to primitive with ID ''{1}''.", o.id, this.id));
+            throw new ClassCastException(tr("Can''t compare primitive with ID ''{0}'' to primitive with ID ''{1}''.", o.id, this.id));
         return new Long(this.version).compareTo(o.version);
     }
@@ -121,4 +130,18 @@
     public Map<String,String> getTags() {
         return Collections.unmodifiableMap(tags);
+    }
+
+    /**
+     * Sets the tags for this history primitive. Removes all
+     * tags if <code>tags</code> is null.
+     * 
+     * @param tags the tags. May be null.
+     */
+    public void setTags(Map<String,String> tags) {
+        if (tags == null) {
+            this.tags = new HashMap<String, String>();
+        } else {
+            this.tags = new HashMap<String, String>(tags);
+        }
     }
 
Index: /trunk/src/org/openstreetmap/josm/gui/dialogs/HistoryDialog.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/dialogs/HistoryDialog.java	(revision 2447)
+++ /trunk/src/org/openstreetmap/josm/gui/dialogs/HistoryDialog.java	(revision 2448)
@@ -37,4 +37,5 @@
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.PrimitiveId;
 import org.openstreetmap.josm.data.osm.history.History;
 import org.openstreetmap.josm.data.osm.history.HistoryDataSet;
@@ -42,5 +43,4 @@
 import org.openstreetmap.josm.gui.OsmPrimitivRenderer;
 import org.openstreetmap.josm.gui.SideButton;
-import org.openstreetmap.josm.gui.history.HistoryBrowserDialog;
 import org.openstreetmap.josm.gui.history.HistoryBrowserDialogManager;
 import org.openstreetmap.josm.gui.history.HistoryLoadTask;
@@ -136,5 +136,5 @@
     }
 
-    public void historyUpdated(HistoryDataSet source, long primitiveId) {
+    public void historyUpdated(HistoryDataSet source, PrimitiveId primitiveId) {
         model.refresh();
     }
@@ -206,5 +206,15 @@
 
         public void selectionChanged(Collection<? extends OsmPrimitive> newSelection) {
-            refresh();
+            data.clear();
+            selectionModel.clearSelection();
+            if (newSelection == null || newSelection.isEmpty()) return;
+            for (OsmPrimitive primitive: newSelection) {
+                if (primitive.isNew()) {
+                    continue;
+                }
+                data.add(primitive);
+            }
+            fireTableDataChanged();
+            selectionModel.addSelectionInterval(0, data.size()-1);
         }
 
@@ -297,26 +307,9 @@
             ArrayList<OsmPrimitive> ret = new ArrayList<OsmPrimitive>(primitives.size());
             for (OsmPrimitive p: primitives) {
-                if (HistoryDataSet.getInstance().getHistory(p.getId()) == null) {
+                if (HistoryDataSet.getInstance().getHistory(p.getPrimitiveId()) == null) {
                     ret.add(p);
                 }
             }
             return ret;
-        }
-
-        /**
-         * shows the {@see HistoryBrowserDialog} for a given {@see History}
-         *
-         * @param h the history. Must not be null.
-         * @exception IllegalArgumentException thrown, if h is null
-         */
-        protected void showHistory(History h) throws IllegalArgumentException {
-            if (h == null)
-                throw new IllegalArgumentException(tr("Parameter ''{0}'' must not be null.", "h"));
-            if (HistoryBrowserDialogManager.getInstance().existsDialog(h.getId())) {
-                HistoryBrowserDialogManager.getInstance().show(h.getId());
-            } else {
-                HistoryBrowserDialog dialog = new HistoryBrowserDialog(h);
-                HistoryBrowserDialogManager.getInstance().show(h.getId(), dialog);
-            }
         }
 
@@ -332,9 +325,9 @@
                 public void run() {
                     for (OsmPrimitive p : primitives) {
-                        History h = HistoryDataSet.getInstance().getHistory(p.getId());
+                        History h = HistoryDataSet.getInstance().getHistory(p.getPrimitiveId());
                         if (h == null) {
                             continue;
                         }
-                        showHistory(h);
+                        HistoryBrowserDialogManager.getInstance().show(h);
                     }
                 }
Index: /trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTable.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTable.java	(revision 2447)
+++ /trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTable.java	(revision 2448)
@@ -20,9 +20,7 @@
 import javax.swing.event.ListSelectionEvent;
 import javax.swing.event.ListSelectionListener;
-import javax.swing.table.TableColumnModel;
 
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.actions.AutoScaleAction;
-import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.gui.layer.Layer;
@@ -191,5 +189,5 @@
         public ZoomToAction() {
             putValue(NAME, tr("Zoom to"));
-            putValue(SHORT_DESCRIPTION, tr("Zoom to primitive the first selected member refers to"));
+            putValue(SHORT_DESCRIPTION, tr("Zoom to the object the first selected member refers to"));
             updateEnabledState();
         }
@@ -220,5 +218,5 @@
             }
             setEnabled(true);
-            putValue(SHORT_DESCRIPTION, tr("Zoom to primitive the first selected member refers to"));
+            putValue(SHORT_DESCRIPTION, tr("Zoom to the object the first selected member refers to"));
         }
 
Index: /trunk/src/org/openstreetmap/josm/gui/help/HelpBrowser.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/help/HelpBrowser.java	(revision 2447)
+++ /trunk/src/org/openstreetmap/josm/gui/help/HelpBrowser.java	(revision 2448)
@@ -175,4 +175,6 @@
      * @return the current URL
      */
+
+
     public String getUrl() {
         return url;
Index: /trunk/src/org/openstreetmap/josm/gui/history/HistoryBrowserDialog.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/history/HistoryBrowserDialog.java	(revision 2447)
+++ /trunk/src/org/openstreetmap/josm/gui/history/HistoryBrowserDialog.java	(revision 2448)
@@ -2,4 +2,5 @@
 package org.openstreetmap.josm.gui.history;
 
+import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
 import static org.openstreetmap.josm.tools.I18n.marktr;
 import static org.openstreetmap.josm.tools.I18n.tr;
@@ -17,4 +18,5 @@
 
 import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.osm.PrimitiveId;
 import org.openstreetmap.josm.data.osm.history.History;
 import org.openstreetmap.josm.data.osm.history.HistoryDataSet;
@@ -24,5 +26,4 @@
 import org.openstreetmap.josm.gui.help.HelpUtil;
 import org.openstreetmap.josm.tools.ImageProvider;
-import static org.openstreetmap.josm.gui.help.HelpUtil.ht;
 
 /**
@@ -35,4 +36,5 @@
     /** the embedded browser */
     private HistoryBrowser browser;
+    private CloseAction closeAction;
 
     /**
@@ -44,7 +46,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(
@@ -70,5 +72,5 @@
         pnl.add(btn);
 
-        btn = new SideButton(new CloseAction());
+        btn = new SideButton(closeAction = new CloseAction());
         btn.setName("btn.close");
         pnl.add(btn);
@@ -106,10 +108,14 @@
     }
 
-    public void historyUpdated(HistoryDataSet source, long primitiveId) {
-        if (primitiveId == browser.getHistory().getId()) {
+    public void historyUpdated(HistoryDataSet source, PrimitiveId primitiveId) {
+        if (primitiveId == null) {
+            browser.populate(source.getHistory(browser.getHistory().getPrimitmiveId()));
+        } else if (primitiveId.equals(browser.getHistory().getPrimitmiveId())) {
             browser.populate(source.getHistory(primitiveId));
-        } else if (primitiveId == 0) {
-            browser.populate(source.getHistory(browser.getHistory().getId()));
         }
+    }
+
+    public void unlinkAsListener() {
+        getHistoryBrowser().getModel().unlinkAsListener();
     }
 
@@ -121,7 +127,12 @@
         }
 
-        public void actionPerformed(ActionEvent e) {
+        public void run() {
+            getHistoryBrowser().getModel().unlinkAsListener();
             HistoryDataSet.getInstance().removeHistoryDataSetListener(HistoryBrowserDialog.this);
             HistoryBrowserDialogManager.getInstance().hide(HistoryBrowserDialog.this);
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            run();
         }
     }
@@ -144,6 +155,5 @@
         @Override
         public void windowClosing(WindowEvent e) {
-            HistoryDataSet.getInstance().removeHistoryDataSetListener(HistoryBrowserDialog.this);
-            HistoryBrowserDialogManager.getInstance().hide(HistoryBrowserDialog.this);
+            closeAction.run();
         }
     }
Index: /trunk/src/org/openstreetmap/josm/gui/history/HistoryBrowserDialogManager.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/history/HistoryBrowserDialogManager.java	(revision 2447)
+++ /trunk/src/org/openstreetmap/josm/gui/history/HistoryBrowserDialogManager.java	(revision 2448)
@@ -4,10 +4,15 @@
 import java.awt.Dimension;
 import java.awt.Point;
+import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Map;
 
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.osm.history.History;
+import org.openstreetmap.josm.gui.layer.Layer;
+import org.openstreetmap.josm.gui.layer.Layer.LayerChangeListener;
 import org.openstreetmap.josm.tools.WindowGeometry;
 
-public class HistoryBrowserDialogManager {
+public class HistoryBrowserDialogManager implements LayerChangeListener {
     static private HistoryBrowserDialogManager instance;
     static public HistoryBrowserDialogManager getInstance() {
@@ -22,4 +27,5 @@
     protected HistoryBrowserDialogManager() {
         dialogs = new HashMap<Long, HistoryBrowserDialog>();
+        Layer.listeners.add(this);
     }
 
@@ -79,3 +85,41 @@
         dialog.dispose();
     }
+
+    /**
+     * Hides and destroys all currently visible history browser dialogs
+     * 
+     */
+    public void hideAll() {
+        ArrayList<HistoryBrowserDialog> dialogs = new ArrayList<HistoryBrowserDialog>();
+        dialogs.addAll(this.dialogs.values());
+        for (HistoryBrowserDialog dialog: dialogs) {
+            dialog.unlinkAsListener();
+            hide(dialog);
+        }
+    }
+
+    public void show(History h) {
+        if (h == null)
+            return;
+        if (existsDialog(h.getId())) {
+            show(h.getId());
+        } else {
+            HistoryBrowserDialog dialog = new HistoryBrowserDialog(h);
+            show(h.getId(), dialog);
+        }
+    }
+
+    /* ----------------------------------------------------------------------------- */
+    /* LayerChangeListener                                                           */
+    /* ----------------------------------------------------------------------------- */
+    public void activeLayerChange(Layer oldLayer, Layer newLayer) {}
+    public void layerAdded(Layer newLayer) {}
+
+    public void layerRemoved(Layer oldLayer) {
+        // remove all history browsers if the number of layers drops to 0
+        //
+        if (Main.map.mapView.getNumLayers() == 0) {
+            hideAll();
+        }
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/gui/history/HistoryBrowserModel.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/history/HistoryBrowserModel.java	(revision 2447)
+++ /trunk/src/org/openstreetmap/josm/gui/history/HistoryBrowserModel.java	(revision 2448)
@@ -5,4 +5,5 @@
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.HashSet;
@@ -12,7 +13,14 @@
 import javax.swing.table.DefaultTableModel;
 
-import org.openstreetmap.josm.data.coor.CoordinateFormat;
-import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.osm.DataSetListener;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
+import org.openstreetmap.josm.data.osm.PrimitiveId;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.data.osm.RelationMember;
+import org.openstreetmap.josm.data.osm.SimplePrimitiveId;
+import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.data.osm.history.History;
 import org.openstreetmap.josm.data.osm.history.HistoryNode;
@@ -20,9 +28,14 @@
 import org.openstreetmap.josm.data.osm.history.HistoryRelation;
 import org.openstreetmap.josm.data.osm.history.HistoryWay;
+import org.openstreetmap.josm.data.osm.visitor.AbstractVisitor;
+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;
 
 /**
  * This is the model used by the history browser.
  *
- * The state this model manages consists of the following elements:
+ * The model state consists of the following elements:
  * <ul>
  *   <li>the {@see History} of a specific {@see OsmPrimitive}</li>
@@ -46,5 +59,5 @@
  * @see HistoryBrowser
  */
-public class HistoryBrowserModel extends Observable {
+public class HistoryBrowserModel extends Observable implements LayerChangeListener, DataSetListener, DataChangeListener {
 
     private static Logger logger = Logger.getLogger(HistoryBrowserModel.class.getName());
@@ -54,4 +67,9 @@
     private HistoryOsmPrimitive reference;
     private HistoryOsmPrimitive current;
+    /**
+     * latest isn't a reference of history. It's a clone of the currently edited
+     * {@see OsmPrimitive} in the current edit layer.
+     */
+    private HistoryOsmPrimitive latest;
 
     private VersionTableModel versionTableModel;
@@ -63,4 +81,7 @@
     private RelationMemberTableModel referenceRelationMemberTableModel;
 
+    /**
+     * constructor
+     */
     public HistoryBrowserModel() {
         versionTableModel = new VersionTableModel();
@@ -71,9 +92,38 @@
         currentRelationMemberTableModel = new RelationMemberTableModel(PointInTimeType.CURRENT_POINT_IN_TIME);
         referenceRelationMemberTableModel = new RelationMemberTableModel(PointInTimeType.REFERENCE_POINT_IN_TIME);
-    }
-
+
+        if (getEditLayer() != null) {
+            getEditLayer().data.addDataSetListener(this);
+            getEditLayer().listenerDataChanged.add(this);
+        }
+        Layer.listeners.add(this);
+
+    }
+
+    /**
+     * Creates a new history browser model for a given history.
+     * 
+     * @param history the history. Must not be null.
+     * @throws IllegalArgumentException thrown if history is null
+     */
     public HistoryBrowserModel(History history) {
         this();
+        if (history == null)
+            throw new IllegalArgumentException(tr("Parameter ''{0}'' must not be null", "history"));
         setHistory(history);
+    }
+
+    /**
+     * Replies the current edit layer; null, if there isn't a current edit layer
+     * of type {@see OsmDataLayer}.
+     * 
+     * @return the current edit layer
+     */
+    protected OsmDataLayer getEditLayer() {
+        try {
+            return Main.map.mapView.getEditLayer();
+        } catch(NullPointerException e) {
+            return null;
+        }
     }
 
@@ -84,4 +134,25 @@
     public History getHistory() {
         return history;
+    }
+
+    protected boolean hasNewNodes(Way way) {
+        for (Node n: way.getNodes()) {
+            if (n.isNew()) return true;
+        }
+        return false;
+    }
+    protected boolean canShowAsLatest(OsmPrimitive primitive) {
+        if (primitive == null) return false;
+        if (primitive.isNew()) return false;
+        if (history == null) return false;
+        // only show latest of the same version if it is
+        // modified
+        if (history.getByVersion(primitive.getVersion()) != null)
+            return primitive.isModified();
+
+        // latest has a higher version than one of the primitives
+        // in the history (probably because the history got out of sync
+        // with uploaded data) -> show the primitive as latest
+        return true;
     }
 
@@ -97,9 +168,16 @@
             current = history.getEarliest();
             reference = history.getEarliest();
+            setLatest(null);
+            if (getEditLayer() != null) {
+                OsmPrimitive p = getEditLayer().data.getPrimitiveById(history.getId(), history.getType());
+                if (canShowAsLatest(p)) {
+                    HistoryOsmPrimitive latest = new HistoryPrimitiveBuilder().build(p);
+                    setLatest(latest);
+                }
+            }
         }
         initTagTableModels();
         fireModelChange();
     }
-
 
     protected void fireModelChange() {
@@ -177,4 +255,16 @@
     }
 
+    /**
+     * Sets the {@see HistoryOsmPrimitive} which plays the role of a reference point
+     * in time (see {@see PointInTimeType}).
+     * 
+     * @param reference the reference history primitive. Must not be null.
+     * @throws IllegalArgumentException thrown if reference is null
+     * @throws IllegalStateException thrown if this model isn't a assigned a history yet
+     * @throws IllegalArgumentException if reference isn't an history primitive for the history managed by this mode
+     * 
+     * @see #setHistory(History)
+     * @see PointInTimeType
+     */
     public void setReferencePointInTime(HistoryOsmPrimitive reference) throws IllegalArgumentException, IllegalStateException{
         if (reference == null)
@@ -196,4 +286,16 @@
     }
 
+    /**
+     * Sets the {@see HistoryOsmPrimitive} which plays the role of the current point
+     * in time (see {@see PointInTimeType}).
+     * 
+     * @param reference the reference history primitive. Must not be null.
+     * @throws IllegalArgumentException thrown if reference is null
+     * @throws IllegalStateException thrown if this model isn't a assigned a history yet
+     * @throws IllegalArgumentException if reference isn't an history primitive for the history managed by this mode
+     * 
+     * @see #setHistory(History)
+     * @see PointInTimeType
+     */
     public void setCurrentPointInTime(HistoryOsmPrimitive current) throws IllegalArgumentException, IllegalStateException{
         if (current == null)
@@ -252,8 +354,21 @@
 
     /**
+     * Returns true if <code>primitive</code> is the latest primitive
+     * representing the version currently edited in the current data
+     * layer.
+     * 
+     * @param primitive the primitive to check
+     * @return true if <code>primitive</code> is the latest primitive
+     */
+    public boolean isLatest(HistoryOsmPrimitive primitive) {
+        if (primitive == null) return false;
+        return primitive == latest;
+    }
+
+    /**
      * The table model for the list of versions in the current history
      *
      */
-    public class VersionTableModel extends DefaultTableModel {
+    public class VersionTableModel extends DefaultTableModel{
 
         private VersionTableModel() {
@@ -264,5 +379,9 @@
             if (history == null)
                 return 0;
-            return history.getNumVersions();
+            int ret = history.getNumVersions();
+            if (latest != null) {
+                ret++;
+            }
+            return ret;
         }
 
@@ -271,5 +390,9 @@
             if(history == null)
                 return null;
-            return history.get(row);
+            if (row < history.getNumVersions())
+                return history.get(row);
+            if (row == history.getNumVersions())
+                return latest;
+            return null;
         }
 
@@ -281,4 +404,10 @@
         public void setReferencePointInTime(int row) {
             if (history == null) return;
+            if (row == history.getNumVersions()) {
+                if (latest != null) {
+                    HistoryBrowserModel.this.setReferencePointInTime(latest);
+                }
+                return;
+            }
             if (row < 0 || row > history.getNumVersions()) return;
             HistoryOsmPrimitive reference = history.get(row);
@@ -288,4 +417,10 @@
         public void setCurrentPointInTime(int row) {
             if (history == null) return;
+            if (row == history.getNumVersions()) {
+                if (latest != null) {
+                    HistoryBrowserModel.this.setCurrentPointInTime(latest);
+                }
+                return;
+            }
             if (row < 0 || row > history.getNumVersions()) return;
             HistoryOsmPrimitive current = history.get(row);
@@ -295,11 +430,24 @@
         public boolean isReferencePointInTime(int row) {
             if (history == null) return false;
+            if (row == history.getNumVersions())
+                return latest == reference;
             if (row < 0 || row > history.getNumVersions()) return false;
             HistoryOsmPrimitive p = history.get(row);
-            return p.equals(reference);
+            return p == reference;
         }
 
         public HistoryOsmPrimitive getPrimitive(int row) {
             return history.get(row);
+        }
+
+        public boolean isLatest(int row) {
+            return row >= history.getNumVersions();
+        }
+
+        public OsmPrimitive getLatest() {
+            if (latest == null) return null;
+            if (getEditLayer() == null) return null;
+            OsmPrimitive p = getEditLayer().data.getPrimitiveById(latest.getId(), latest.getType());
+            return p;
         }
     }
@@ -467,4 +615,11 @@
                 return null;
             return way.getNodes().get(row);
+        }
+
+        public PrimitiveId getNodeId(int row) {
+            HistoryWay way = getWay();
+            if (way == null) return null;
+            if (row > way.getNumNodes()) return null;
+            return new SimplePrimitiveId(way.getNodeId(row), OsmPrimitiveType.NODE);
         }
 
@@ -587,3 +742,164 @@
         }
     }
+
+    protected void setLatest(HistoryOsmPrimitive latest) {
+        if (latest == null) {
+            if (this.current == this.latest) {
+                this.current = history.getLatest();
+            }
+            if (this.reference == this.latest) {
+                this.current = history.getLatest();
+            }
+            this.latest = null;
+        } else {
+            if (this.current == this.latest) {
+                this.current = latest;
+            }
+            if (this.reference == this.latest) {
+                this.reference = latest;
+            }
+            this.latest = latest;
+        }
+        fireModelChange();
+    }
+
+    /**
+     * Removes this model as listener for data change and layer change
+     * events.
+     * 
+     */
+    public void unlinkAsListener() {
+        if (getEditLayer() != null) {
+            getEditLayer().data.removeDataSetListener(this);
+        }
+        Layer.listeners.remove(this);
+
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* DataSetListener                                                        */
+    /* ---------------------------------------------------------------------- */
+    public void nodeMoved(Node node) {
+        if (!node.isNew() && node.getId() == history.getId()) {
+            setLatest(new HistoryPrimitiveBuilder().build(node));
+        }
+    }
+
+    public void primtivesAdded(Collection<? extends OsmPrimitive> added) {
+        if (added == null || added.isEmpty()) return;
+        for (OsmPrimitive p: added) {
+            if (canShowAsLatest(p)) {
+                setLatest(new HistoryPrimitiveBuilder().build(p));
+            }
+        }
+    }
+
+    public void primtivesRemoved(Collection<? extends OsmPrimitive> removed) {
+        if (removed == null || removed.isEmpty()) return;
+        for (OsmPrimitive p: removed) {
+            if (!p.isNew() && p.getId() == history.getId()) {
+                setLatest(null);
+            }
+        }
+    }
+
+    public void relationMembersChanged(Relation r) {
+        if (!r.isNew() && r.getId() == history.getId()) {
+            setLatest(new HistoryPrimitiveBuilder().build(r));
+        }
+    }
+
+    public void tagsChanged(OsmPrimitive prim) {
+        if (!prim.isNew() && prim.getId() == history.getId()) {
+            setLatest(new HistoryPrimitiveBuilder().build(prim));
+        }
+    }
+
+    public void wayNodesChanged(Way way) {
+        if (!way.isNew() && way.getId() == history.getId()) {
+            setLatest(new HistoryPrimitiveBuilder().build(way));
+        }
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* DataChangeListener                                                    */
+    /* ---------------------------------------------------------------------- */
+    public void dataChanged(OsmDataLayer l) {
+        if (l != getEditLayer()) return;
+        OsmPrimitive primitive = l.data.getPrimitiveById(history.getId(), history.getType());
+        HistoryOsmPrimitive latest;
+        if (canShowAsLatest(primitive)) {
+            latest = new HistoryPrimitiveBuilder().build(primitive);
+        } else {
+            latest = null;
+        }
+        setLatest(latest);
+        fireModelChange();
+    }
+
+    /* ---------------------------------------------------------------------- */
+    /* LayerChangeListener                                                    */
+    /* ---------------------------------------------------------------------- */
+    public void activeLayerChange(Layer oldLayer, Layer newLayer) {
+        if (oldLayer != null && oldLayer instanceof OsmDataLayer) {
+            OsmDataLayer l = (OsmDataLayer)oldLayer;
+            l.data.removeDataSetListener(this);
+            l.listenerDataChanged.remove(this);
+        }
+        if (newLayer == null || ! (newLayer instanceof OsmDataLayer)) {
+            latest = null;
+            fireModelChange();
+            return;
+        }
+        OsmDataLayer l = (OsmDataLayer)newLayer;
+        l.data.addDataSetListener(this);
+        l.listenerDataChanged.add(this);
+        OsmPrimitive primitive = l.data.getPrimitiveById(history.getId(), history.getType());
+        HistoryOsmPrimitive latest;
+        if (canShowAsLatest(primitive)) {
+            latest = new HistoryPrimitiveBuilder().build(primitive);
+        } else {
+            latest = null;
+        }
+        setLatest(latest);
+        fireModelChange();
+    }
+
+    public void layerAdded(Layer newLayer) {}
+    public void layerRemoved(Layer oldLayer) {}
+
+    /**
+     * Creates a {@see HistoryOsmPrimitive} from a {@see OsmPrimitive}
+     * 
+     */
+    class HistoryPrimitiveBuilder extends AbstractVisitor {
+        private HistoryOsmPrimitive clone;
+
+        public void visit(Node n) {
+            clone = new HistoryNode(n.getId(), n.getVersion(), n.isVisible(),n.getUser().getName(), n.getUser().getId(), 0, n.getTimestamp(), n.getCoor());
+            clone.setTags(n.getKeys());
+        }
+
+        public void visit(Relation r) {
+            clone = new HistoryRelation(r.getId(), r.getVersion(), r.isVisible(),r.getUser().getName(), r.getUser().getId(), 0, r.getTimestamp());
+            clone.setTags(r.getKeys());
+            HistoryRelation hr = (HistoryRelation)clone;
+            for (RelationMember rm : r.getMembers()) {
+                hr.addMember(new org.openstreetmap.josm.data.osm.history.RelationMember(rm.getRole(), rm.getType(), rm.getUniqueId()));
+            }
+        }
+
+        public void visit(Way w) {
+            clone = new HistoryWay(w.getId(), w.getVersion(), w.isVisible(),w.getUser().getName(), w.getUser().getId(), 0, w.getTimestamp());
+            clone.setTags(w.getKeys());
+            for (Node n: w.getNodes()) {
+                ((HistoryWay)clone).addNode(n.getUniqueId());
+            }
+        }
+
+        public HistoryOsmPrimitive build(OsmPrimitive primitive) {
+            primitive.visit(this);
+            return clone;
+        }
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/gui/history/HistoryLoadTask.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/history/HistoryLoadTask.java	(revision 2447)
+++ /trunk/src/org/openstreetmap/josm/gui/history/HistoryLoadTask.java	(revision 2448)
@@ -7,9 +7,10 @@
 import java.io.IOException;
 import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
+import java.util.HashSet;
 
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
+import org.openstreetmap.josm.data.osm.PrimitiveId;
+import org.openstreetmap.josm.data.osm.SimplePrimitiveId;
 import org.openstreetmap.josm.data.osm.history.History;
 import org.openstreetmap.josm.data.osm.history.HistoryDataSet;
@@ -45,10 +46,10 @@
     private boolean cancelled = false;
     private Exception lastException  = null;
-    private Map<Long, OsmPrimitiveType> toLoad;
+    private HashSet<PrimitiveId> toLoad;
     private HistoryDataSet loadedData;
 
     public HistoryLoadTask() {
         super(tr("Load history"), true);
-        toLoad = new HashMap<Long, OsmPrimitiveType>();
+        toLoad = new HashSet<PrimitiveId>();
     }
 
@@ -60,12 +61,26 @@
      * @return this task
      */
-    public HistoryLoadTask add(long id, OsmPrimitiveType type) {
+    public HistoryLoadTask add(long id, OsmPrimitiveType type) throws IllegalArgumentException {
         if (id <= 0)
-            throw new IllegalArgumentException(tr("ID > 0 expected. Got {0}.", id));
+            throw new IllegalArgumentException(tr("Parameter ''{0}'' > 0 expected. Got {1}.", "id", id));
         if (type == null)
             throw new IllegalArgumentException(tr("Parameter ''{0}'' must not be null.", "type"));
-        if (!toLoad.containsKey(id)) {
-            toLoad.put(id, type);
-        }
+        SimplePrimitiveId pid = new SimplePrimitiveId(id, type);
+        toLoad.add(pid);
+        return this;
+    }
+
+    /**
+     * Adds an object whose history is to be loaded.
+     * 
+     * @param pid  the primitive id. Must not be null. Id > 0 required.
+     * @return this task
+     */
+    public HistoryLoadTask add(PrimitiveId pid) throws IllegalArgumentException {
+        if (pid == null)
+            throw new IllegalArgumentException(tr("Parameter ''{0}'' must not be null.", "pid"));
+        if (pid.getUniqueId() <= 0)
+            throw new IllegalArgumentException(tr("id in parameter ''{0}'' > 0 expected, got {1}.", "pid", pid.getUniqueId()));
+        toLoad.add(pid);
         return this;
     }
@@ -81,7 +96,5 @@
         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());
-        }
+        toLoad.add(primitive.getPrimitiveId());
         return this;
     }
@@ -97,7 +110,5 @@
         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());
-        }
+        toLoad.add(history.getPrimitmiveId());
         return this;
     }
@@ -116,6 +127,6 @@
         if (primitive.getId() <= 0)
             throw new IllegalArgumentException(tr("Object id > 0 expected. Got {0}", primitive.getId()));
-
-        return add(primitive.getId(), OsmPrimitiveType.from(primitive));
+        toLoad.add(primitive.getPrimitiveId());
+        return this;
     }
 
@@ -161,23 +172,20 @@
         loadedData = new HistoryDataSet();
         try {
-            for(Map.Entry<Long, OsmPrimitiveType> entry: toLoad.entrySet()) {
+            for(PrimitiveId pid: toLoad) {
                 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;
+                switch(pid.getType()) {
+                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())));
+                        Long.toString(pid.getUniqueId())));
                 OsmServerHistoryReader reader = null;
                 HistoryDataSet ds = null;
                 try {
-                    reader = new OsmServerHistoryReader(entry.getValue(), entry.getKey());
+                    reader = new OsmServerHistoryReader(pid.getType(), pid.getUniqueId());
                     ds = reader.parseHistory(progressMonitor.createSubTaskMonitor(1, false));
                 } catch(OsmTransferException e) {
Index: /trunk/src/org/openstreetmap/josm/gui/history/NodeListViewer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/history/NodeListViewer.java	(revision 2447)
+++ /trunk/src/org/openstreetmap/josm/gui/history/NodeListViewer.java	(revision 2448)
@@ -1,13 +1,31 @@
 // License: GPL. For details, see LICENSE file.
 package org.openstreetmap.josm.gui.history;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
 
 import java.awt.GridBagConstraints;
 import java.awt.GridBagLayout;
 import java.awt.Insets;
-
+import java.awt.Point;
+import java.awt.event.ActionEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+
+import javax.swing.AbstractAction;
 import javax.swing.JPanel;
+import javax.swing.JPopupMenu;
 import javax.swing.JScrollPane;
 import javax.swing.JTable;
 import javax.swing.ListSelectionModel;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.AutoScaleAction;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.PrimitiveId;
+import org.openstreetmap.josm.data.osm.history.History;
+import org.openstreetmap.josm.data.osm.history.HistoryDataSet;
+import org.openstreetmap.josm.gui.history.HistoryBrowserModel.NodeListTableModel;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.tools.ImageProvider;
 
 /**
@@ -28,4 +46,5 @@
     private AdjustmentSynchronizer adjustmentSynchronizer;
     private SelectionSynchronizer selectionSynchronizer;
+    private NodeListPopupMenu popupMenu;
 
     protected JScrollPane embeddInScrollPane(JTable table) {
@@ -45,4 +64,6 @@
         table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
         selectionSynchronizer.participateInSynchronizedSelection(table.getSelectionModel());
+        table.addMouseListener(new PopupMenuLauncher(table));
+        table.addMouseListener(new DoubleClickAdapter(table));
         return table;
     }
@@ -56,4 +77,6 @@
         table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
         selectionSynchronizer.participateInSynchronizedSelection(table.getSelectionModel());
+        table.addMouseListener(new PopupMenuLauncher(table));
+        table.addMouseListener(new DoubleClickAdapter(table));
         return table;
     }
@@ -110,4 +133,6 @@
         gc.anchor = GridBagConstraints.NORTHWEST;
         add(embeddInScrollPane(buildCurrentNodeListTable()),gc);
+
+        popupMenu = new NodeListPopupMenu();
     }
 
@@ -143,3 +168,162 @@
         }
     }
+
+
+    class NodeListPopupMenu extends JPopupMenu {
+        private ZoomToNodeAction zoomToNodeAction;
+        private ShowHistoryAction showHistoryAction;
+
+        public NodeListPopupMenu() {
+            zoomToNodeAction = new ZoomToNodeAction();
+            add(zoomToNodeAction);
+            showHistoryAction = new ShowHistoryAction();
+            add(showHistoryAction);
+        }
+
+        public void prepare(PrimitiveId pid){
+            zoomToNodeAction.setPrimitiveId(pid);
+            zoomToNodeAction.updateEnabledState();
+
+            showHistoryAction.setPrimitiveId(pid);
+            showHistoryAction.updateEnabledState();
+        }
+    }
+
+    class ZoomToNodeAction extends AbstractAction {
+        private PrimitiveId primitiveId;
+
+        public ZoomToNodeAction() {
+            putValue(NAME, tr("Zoom to node"));
+            putValue(SHORT_DESCRIPTION, tr("Zoom to this node in the current data layer"));
+            putValue(SMALL_ICON, ImageProvider.get("dialogs", "zoomin"));
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            if (!isEnabled()) return;
+            OsmPrimitive p = getPrimitiveToZoom();
+            if (p!= null) {
+                getEditLayer().data.setSelected(p.getPrimitiveId());
+                new AutoScaleAction("selection").autoScale();
+            }
+        }
+
+        public void setPrimitiveId(PrimitiveId pid) {
+            this.primitiveId = pid;
+            updateEnabledState();
+        }
+
+        protected OsmDataLayer getEditLayer() {
+            try {
+                return Main.map.mapView.getEditLayer();
+            } catch(NullPointerException e) {
+                return null;
+            }
+        }
+
+        protected OsmPrimitive getPrimitiveToZoom() {
+            if (primitiveId == null) return null;
+            OsmPrimitive p = getEditLayer().data.getPrimitiveById(primitiveId);
+            return p;
+        }
+
+        public void updateEnabledState() {
+            if (getEditLayer() == null) {
+                setEnabled(false);
+                return;
+            }
+            setEnabled(getPrimitiveToZoom() != null);
+        }
+    }
+
+    class ShowHistoryAction extends AbstractAction {
+        private PrimitiveId primitiveId;
+
+        public ShowHistoryAction() {
+            putValue(NAME, tr("Show history"));
+            putValue(SHORT_DESCRIPTION, tr("Open a history browser with the history of this node"));
+            putValue(SMALL_ICON, ImageProvider.get("dialogs", "history"));
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            if (!isEnabled()) return;
+            run();
+        }
+
+        public void setPrimitiveId(PrimitiveId pid) {
+            this.primitiveId = pid;
+            updateEnabledState();
+        }
+
+        public void run() {
+            if (HistoryDataSet.getInstance().getHistory(primitiveId) == null) {
+                Main.worker.submit(new HistoryLoadTask().add(primitiveId));
+            }
+            Runnable r = new Runnable() {
+                public void run() {
+                    History h = HistoryDataSet.getInstance().getHistory(primitiveId);
+                    if (h == null)
+                        return;
+                    HistoryBrowserDialogManager.getInstance().show(h);
+                }
+            };
+            Main.worker.submit(r);
+        }
+
+        public void updateEnabledState() {
+            setEnabled(primitiveId != null && primitiveId.getUniqueId() > 0);
+        }
+    }
+
+    class PopupMenuLauncher extends MouseAdapter {
+        private JTable table;
+
+        public PopupMenuLauncher(JTable table) {
+            this.table = table;
+        }
+
+        @Override
+        public void mousePressed(MouseEvent e) {
+            showPopup(e);
+        }
+
+        @Override
+        public void mouseReleased(MouseEvent e) {
+            showPopup(e);
+        }
+
+        private void showPopup(MouseEvent e) {
+            if (!e.isPopupTrigger()) return;
+            Point p = e.getPoint();
+            int row = table.rowAtPoint(p);
+            NodeListTableModel model = (NodeListTableModel) table.getModel();
+            PrimitiveId pid = model.getNodeId(row);
+            popupMenu.prepare(pid);
+            popupMenu.show(e.getComponent(), e.getX(), e.getY());
+        }
+    }
+
+    class DoubleClickAdapter extends MouseAdapter {
+        private JTable table;
+        private ShowHistoryAction showHistoryAction;
+
+        public DoubleClickAdapter(JTable table) {
+            this.table = table;
+            showHistoryAction = new ShowHistoryAction();
+        }
+
+        protected NodeListTableModel getModel() {
+            return (NodeListTableModel)table.getModel();
+        }
+
+        @Override
+        public void mouseClicked(MouseEvent e) {
+            if (e.getClickCount() < 2) return;
+            int row = table.rowAtPoint(e.getPoint());
+            PrimitiveId pid = getModel().getNodeId(row);
+            if (pid == null)
+                return;
+            showHistoryAction.setPrimitiveId(pid);
+            showHistoryAction.run();
+        }
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/gui/history/TagTableCellRenderer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/history/TagTableCellRenderer.java	(revision 2447)
+++ /trunk/src/org/openstreetmap/josm/gui/history/TagTableCellRenderer.java	(revision 2448)
@@ -6,8 +6,10 @@
 import java.awt.Color;
 import java.awt.Component;
+import java.awt.Font;
 import java.util.logging.Logger;
 
 import javax.swing.JLabel;
 import javax.swing.JTable;
+import javax.swing.UIManager;
 import javax.swing.table.TableCellRenderer;
 
@@ -20,35 +22,43 @@
     static private Logger logger = Logger.getLogger(TagTableCellRenderer.class.getName());
 
-    public final static Color BGCOLOR_SELECTED = new Color(143,170,255);
     public final static Color BGCOLOR_DIFFERENCE = new Color(255,197,197);
 
     public TagTableCellRenderer() {
         setOpaque(true);
-        setForeground(Color.BLACK);
     }
 
     protected void renderName(String key, HistoryBrowserModel.TagTableModel model, boolean isSelected) {
         String text = key;
-        Color bgColor = Color.WHITE;
+        Color bgColor = UIManager.getColor("Table.background");
+        Color fgColor = UIManager.getColor("Table.foreground");
+        Font font = UIManager.getFont("Table.font");
         if (! model.hasTag(key)) {
-            text = tr("<undefined>");
+            text = tr("not present");
             bgColor = BGCOLOR_DIFFERENCE;
+            font = font.deriveFont(Font.ITALIC);
         } else if (!model.oppositeHasTag(key)) {
             bgColor = BGCOLOR_DIFFERENCE;
         }
         if (isSelected) {
-            bgColor = BGCOLOR_SELECTED;
+            bgColor = UIManager.getColor("Table.backgroundSelected");
+            fgColor = UIManager.getColor("Table.foregroundSelected");
         }
+
         setText(text);
         setToolTipText(text);
         setBackground(bgColor);
+        setForeground(fgColor);
+        setFont(font);
     }
 
     protected void renderValue(String key, HistoryBrowserModel.TagTableModel model, boolean isSelected) {
         String text = "";
-        Color bgColor = Color.WHITE;
+        Color bgColor = UIManager.getColor("Table.background");
+        Color fgColor = UIManager.getColor("Table.foreground");
+        Font font = UIManager.getFont("Table.font");
         if (! model.hasTag(key)) {
-            text = tr("<undefined>");
+            text = tr("not present");
             bgColor = BGCOLOR_DIFFERENCE;
+            font = font.deriveFont(Font.ITALIC);
         } else {
             text = model.getValue(key);
@@ -58,5 +68,6 @@
         }
         if (isSelected) {
-            bgColor = BGCOLOR_SELECTED;
+            bgColor = UIManager.getColor("Table.backgroundSelected");
+            fgColor = UIManager.getColor("Table.foregroundSelected");
         }
 
@@ -64,4 +75,6 @@
         setToolTipText(text);
         setBackground(bgColor);
+        setForeground(fgColor);
+        setFont(font);
     }
 
Index: /trunk/src/org/openstreetmap/josm/gui/history/VersionInfoPanel.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/history/VersionInfoPanel.java	(revision 2447)
+++ /trunk/src/org/openstreetmap/josm/gui/history/VersionInfoPanel.java	(revision 2448)
@@ -4,4 +4,5 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
+import java.awt.BorderLayout;
 import java.awt.FlowLayout;
 import java.awt.GridBagConstraints;
@@ -17,6 +18,9 @@
 import javax.swing.JPanel;
 
+import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.actions.AbstractInfoAction;
 import org.openstreetmap.josm.data.osm.history.HistoryOsmPrimitive;
+import org.openstreetmap.josm.gui.JMultilineLabel;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.tools.UrlLabel;
 
@@ -31,23 +35,24 @@
     private PointInTimeType pointInTimeType;
     private HistoryBrowserModel model;
-    private JLabel lblInfo;
+    private JMultilineLabel lblInfo;
     private UrlLabel lblUser;
     private UrlLabel lblChangeset;
+    private JPanel pnlUserAndChangeset;
 
     protected void build() {
         JPanel pnl1 = new JPanel();
-        pnl1.setLayout(new FlowLayout(FlowLayout.LEFT));
-        lblInfo = new JLabel();
-        lblInfo.setHorizontalAlignment(JLabel.LEFT);
-        pnl1.add(lblInfo);
+        pnl1.setLayout(new BorderLayout());
+        lblInfo = new JMultilineLabel("");
+        //lblInfo.setHorizontalAlignment(JLabel.LEFT);
+        pnl1.add(lblInfo, BorderLayout.CENTER);
 
-        JPanel pnl2 = new JPanel();
-        pnl2.setLayout(new FlowLayout(FlowLayout.LEFT));
+        pnlUserAndChangeset = new JPanel();
+        pnlUserAndChangeset.setLayout(new FlowLayout(FlowLayout.LEFT));
         lblUser = new UrlLabel();
-        pnl2.add(new JLabel(tr("User")));
-        pnl2.add(lblUser);
-        pnl2.add(new JLabel(tr("Changeset")));
+        pnlUserAndChangeset.add(new JLabel(tr("User")));
+        pnlUserAndChangeset.add(lblUser);
+        pnlUserAndChangeset.add(new JLabel(tr("Changeset")));
         lblChangeset = new UrlLabel();
-        pnl2.add(lblChangeset);
+        pnlUserAndChangeset.add(lblChangeset);
 
         setLayout(new GridBagLayout());
@@ -56,8 +61,9 @@
         gc.fill = GridBagConstraints.HORIZONTAL;
         gc.weightx = 1.0;
-        gc.weighty = 0.0;
+        gc.weighty = 1.0;
         add(pnl1, gc);
         gc.gridy = 1;
-        add(pnl2, gc);
+        gc.weighty = 0.0;
+        add(pnlUserAndChangeset, gc);
     }
 
@@ -68,13 +74,29 @@
     }
 
+    protected OsmDataLayer getEditLayer() {
+        try {
+            return Main.map.mapView.getEditLayer();
+        } catch(NullPointerException e) {
+            return null;
+        }
+    }
+
     protected String getInfoText() {
         HistoryOsmPrimitive primitive = getPrimitive();
         if (primitive == null)
             return "";
-        String text = tr(
-                "<html>Version <strong>{0}</strong> created on <strong>{1}</strong></html>",
-                Long.toString(primitive.getVersion()),
-                new SimpleDateFormat().format(primitive.getTimestamp())
-        );
+        String text;
+        if (model.isLatest(primitive)) {
+            text = tr("<html>Version <strong>{0}</strong> currently edited in layer ''{1}''</html>",
+                    Long.toString(primitive.getVersion()),
+                    getEditLayer() == null ? tr("unknown") : getEditLayer().getName()
+            );
+        } else {
+            text = tr(
+                    "<html>Version <strong>{0}</strong> created on <strong>{1}</strong></html>",
+                    Long.toString(primitive.getVersion()),
+                    new SimpleDateFormat().format(primitive.getTimestamp())
+            );
+        }
         return text;
     }
@@ -110,21 +132,39 @@
         lblInfo.setText(getInfoText());
 
-        String url = AbstractInfoAction.getBaseBrowseUrl() + "/changeset/" + getPrimitive().getChangesetId();
-        lblChangeset.setUrl(url);
-        lblChangeset.setDescription(Long.toString(getPrimitive().getChangesetId()));
+        if (!model.isLatest(getPrimitive())) {
+            String url = AbstractInfoAction.getBaseBrowseUrl() + "/changeset/" + getPrimitive().getChangesetId();
+            lblChangeset.setUrl(url);
+            lblChangeset.setDescription(Long.toString(getPrimitive().getChangesetId()));
 
-        try {
-            if (getPrimitive().getUid() != -1) {
-                url = AbstractInfoAction.getBaseUserUrl() + "/" +  URLEncoder.encode(getPrimitive().getUser(), "UTF-8").replaceAll("\\+", "%20");
-                lblUser.setUrl(url);
-            } else {
+            try {
+                if (getPrimitive().getUid() != -1) {
+                    url = AbstractInfoAction.getBaseUserUrl() + "/" +  URLEncoder.encode(getPrimitive().getUser(), "UTF-8").replaceAll("\\+", "%20");
+                    lblUser.setUrl(url);
+                } else {
+                    lblUser.setUrl(null);
+                }
+            } catch(UnsupportedEncodingException e) {
+                e.printStackTrace();
                 lblUser.setUrl(null);
             }
-        } catch(UnsupportedEncodingException e) {
-            e.printStackTrace();
-            lblUser.setUrl(null);
+            String username = getPrimitive().getUser();
+            lblUser.setDescription(username);
+        } else {
+            String user = Main.pref.get("osm-server.username");
+            if (user == null) {
+                lblUser.setDescription(tr("anonymous"));
+            } else {
+                try {
+                    String url = AbstractInfoAction.getBaseUserUrl() + "/" +  URLEncoder.encode(user, "UTF-8").replaceAll("\\+", "%20");
+                    lblUser.setUrl(url);
+                } catch(UnsupportedEncodingException e) {
+                    e.printStackTrace();
+                    lblUser.setUrl(null);
+                }
+                lblUser.setDescription(user);
+            }
+            lblChangeset.setDescription(tr("none"));
+            lblChangeset.setUrl(null);
         }
-        String username = getPrimitive().getUser();
-        lblUser.setDescription(username);
     }
 }
Index: /trunk/src/org/openstreetmap/josm/gui/history/VersionTableCellRenderer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/history/VersionTableCellRenderer.java	(revision 2447)
+++ /trunk/src/org/openstreetmap/josm/gui/history/VersionTableCellRenderer.java	(revision 2448)
@@ -15,6 +15,9 @@
 import javax.swing.table.TableCellRenderer;
 
+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.HistoryOsmPrimitive;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.tools.ImageProvider;
 
@@ -44,14 +47,11 @@
     }
 
-    protected void renderIcon(HistoryOsmPrimitive primitive) {
-        ImageIcon icon = null;
-        if (primitive != null) {
-            icon = icons.get(primitive.getType());
-        }
+    protected void renderIcon(OsmPrimitiveType type) {
+        ImageIcon icon = type == null? null : icons.get(type);
         setIcon(icon);
     }
 
     protected void renderText(HistoryOsmPrimitive primitive) {
-        // render lable text
+        // render label text
         //
         StringBuilder sb = new StringBuilder();
@@ -86,4 +86,42 @@
     }
 
+    protected OsmDataLayer getEditLayer() {
+        try {
+            return Main.map.mapView.getEditLayer();
+        } catch(NullPointerException e) {
+            return null;
+        }
+    }
+
+    protected void renderLatestText(OsmPrimitive primitive) {
+        // -- label text
+        StringBuffer sb = new StringBuffer();
+        if (primitive == null) {
+            setText("");
+            return;
+        }
+        if (primitive.isModified()) {
+            sb.append("*");
+        }
+        sb.append(tr("Version {0} in editor", primitive.getVersion()));
+        if (primitive.isDeleted()) {
+            sb.append(tr("[deleted]"));
+        }
+        setText(sb.toString());
+
+        // -- tooltip text
+        sb = new StringBuffer();
+        OsmDataLayer l = getEditLayer();
+
+        sb.append(
+                tr(
+                        "Version {0} currently edited in data layer ''{1}''",
+                        primitive.getId(),
+                        l == null ? tr("unknown") : l.getName()
+                )
+        );
+        setToolTipText(sb.toString());
+    }
+
     protected void renderBackground(JTable table, int row, boolean isSelected) {
         Color bgColor = Color.WHITE;
@@ -96,11 +134,23 @@
     }
 
+    public void renderVersionFromHistory(HistoryOsmPrimitive primitive, JTable table, int row, boolean isSelected) {
+        renderIcon(primitive.getType());
+        renderText(primitive);
+        renderBackground(table, row, isSelected);
+    }
+
+    public void renderLatest(OsmPrimitive primitive, JTable table, int row, boolean isSelected) {
+        renderIcon(primitive.getType());
+        renderLatestText(getModel(table).getLatest());
+        renderBackground(table, row, isSelected);
+    }
+
     public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
             int row, int column) {
-
-        HistoryOsmPrimitive primitive = (HistoryOsmPrimitive)value;
-        renderIcon(primitive);
-        renderText(primitive);
-        renderBackground(table, row, isSelected);
+        if (getModel(table).isLatest(row)) {
+            renderLatest(getModel(table).getLatest(),table, row, isSelected);
+        } else {
+            renderVersionFromHistory((HistoryOsmPrimitive)value, table, row, isSelected);
+        }
         return this;
     }
Index: /trunk/test/functional/org/openstreetmap/josm/gui/history/HistoryBrowserTest.java
===================================================================
--- /trunk/test/functional/org/openstreetmap/josm/gui/history/HistoryBrowserTest.java	(revision 2447)
+++ /trunk/test/functional/org/openstreetmap/josm/gui/history/HistoryBrowserTest.java	(revision 2448)
@@ -16,4 +16,5 @@
 import org.openstreetmap.josm.Main;
 import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
+import org.openstreetmap.josm.data.osm.SimplePrimitiveId;
 import org.openstreetmap.josm.data.osm.history.History;
 import org.openstreetmap.josm.data.osm.history.HistoryDataSet;
@@ -78,5 +79,5 @@
             return;
         }
-        History h = ds.getHistory(id);
+        History h = ds.getHistory(new SimplePrimitiveId(id, type));
         browser.populate(h);
     }
Index: /trunk/test/functional/org/openstreetmap/josm/io/OsmServerHistoryReaderTest.java
===================================================================
--- /trunk/test/functional/org/openstreetmap/josm/io/OsmServerHistoryReaderTest.java	(revision 2447)
+++ /trunk/test/functional/org/openstreetmap/josm/io/OsmServerHistoryReaderTest.java	(revision 2448)
@@ -22,5 +22,5 @@
         OsmServerHistoryReader reader = new OsmServerHistoryReader(OsmPrimitiveType.NODE,266187);
         HistoryDataSet ds = reader.parseHistory(NullProgressMonitor.INSTANCE);
-        History h = ds.getHistory(266187);
+        History h = ds.getHistory(266187, OsmPrimitiveType.NODE);
         System.out.println("num versions: " + h.getNumVersions());
     }
@@ -30,5 +30,5 @@
         OsmServerHistoryReader reader = new OsmServerHistoryReader(OsmPrimitiveType.WAY,32916);
         HistoryDataSet ds = reader.parseHistory(NullProgressMonitor.INSTANCE);
-        History h = ds.getHistory(32916);
+        History h = ds.getHistory(32916, OsmPrimitiveType.WAY);
         System.out.println("num versions: " + h.getNumVersions());
     }
@@ -38,5 +38,5 @@
         OsmServerHistoryReader reader = new OsmServerHistoryReader(OsmPrimitiveType.RELATION,49);
         HistoryDataSet ds = reader.parseHistory(NullProgressMonitor.INSTANCE);
-        History h = ds.getHistory(49);
+        History h = ds.getHistory(49, OsmPrimitiveType.RELATION);
         System.out.println("num versions: " + h.getNumVersions());
     }
