Index: /trunk/src/org/openstreetmap/josm/command/TagConflictResolveCommand.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/command/TagConflictResolveCommand.java	(revision 1641)
+++ /trunk/src/org/openstreetmap/josm/command/TagConflictResolveCommand.java	(revision 1642)
@@ -25,19 +25,19 @@
  */
 public class TagConflictResolveCommand extends Command {
-    
+
     /** my primitive (in the local dataset). merge decisions are applied to this
      *  primitive
      */
-    private OsmPrimitive my;
-    /** their primitive (in the server dataset) */ 
-    private OsmPrimitive their;
-    
+    private final OsmPrimitive my;
+    /** their primitive (in the server dataset) */
+    private final OsmPrimitive their;
+
     /** the list of merge decisions, represented as {@see TagMergeItem}s */
-    private List<TagMergeItem> mergeItems; 
-    
+    private final List<TagMergeItem> mergeItems;
+
     /**
      * replies the number of decided conflicts
      * 
-     * @return the number of decided conflicts 
+     * @return the number of decided conflicts
      */
     public int getNumDecidedConflicts() {
@@ -45,10 +45,10 @@
         for (TagMergeItem item: mergeItems) {
             if (!item.getMergeDecision().equals(MergeDecisionType.UNDECIDED)) {
-                n++; 
+                n++;
             }
         }
         return n;
     }
-    
+
     /**
      * replies a (localized) display name for the type of an OSM primitive
@@ -63,10 +63,10 @@
         return "";
     }
-    
+
     /**
-     * constructor 
+     * constructor
      * 
      * @param my  my primitive
-     * @param their  their primitive 
+     * @param their  their primitive
      * @param mergeItems the list of merge decisions, represented as {@see TagMergeItem}s
      */
@@ -76,15 +76,15 @@
         this.mergeItems = mergeItems;
     }
-    
-    
+
+
     @Override
-    public MutableTreeNode description() {                
+    public MutableTreeNode description() {
         return new DefaultMutableTreeNode(
-          new JLabel(
-             tr("Resolve {0} tag conflicts in {1} {2}",getNumDecidedConflicts(), getPrimitiveTypeAsString(my), my.id), 
-             ImageProvider.get("data", "object"), 
-             JLabel.HORIZONTAL
-          )
-       );
+                new JLabel(
+                        tr("Resolve {0} tag conflicts in {1} {2}",getNumDecidedConflicts(), getPrimitiveTypeAsString(my), my.id),
+                        ImageProvider.get("data", "object"),
+                        JLabel.HORIZONTAL
+                )
+        );
     }
 
@@ -95,9 +95,11 @@
         //
         super.executeCommand();
-        
+
         // apply the merge decisions to OSM primitive 'my'
         //
         for (TagMergeItem item: mergeItems) {
-            item.applyToMyPrimitive(my);
+            if (! item.getMergeDecision().equals(MergeDecisionType.UNDECIDED)) {
+                item.applyToMyPrimitive(my);
+            }
         }
         return true;
@@ -115,5 +117,5 @@
         //
         super.undoCommand();
-        
+
         // restore a conflict if necessary
         //
@@ -123,4 +125,4 @@
     }
 
-    
+
 }
Index: /trunk/src/org/openstreetmap/josm/command/VersionConflictResolveCommand.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/command/VersionConflictResolveCommand.java	(revision 1641)
+++ /trunk/src/org/openstreetmap/josm/command/VersionConflictResolveCommand.java	(revision 1642)
@@ -24,17 +24,17 @@
 public class VersionConflictResolveCommand extends Command {
 
-    private OsmPrimitive my;
-    private OsmPrimitive their;
-    
+    private final OsmPrimitive my;
+    private final OsmPrimitive their;
+
     /**
-     * constructor 
-     * @param my  my primitive (i.e. the primitive from the local dataset) 
-     * @param their their primitive (i.e. the primitive from the server) 
+     * constructor
+     * @param my  my primitive (i.e. the primitive from the local dataset)
+     * @param their their primitive (i.e. the primitive from the server)
      */
     public VersionConflictResolveCommand(OsmPrimitive my, OsmPrimitive their) {
-      this.my = my;
-      this.their = their; 
+        this.my = my;
+        this.their = their;
     }
-    
+
     //FIXME copied from TagConflictResolveCommand -> refactor
     /**
@@ -50,14 +50,14 @@
         return "";
     }
-    
+
     @Override
     public MutableTreeNode description() {
         return new DefaultMutableTreeNode(
-            new JLabel(
-               tr("Resolve version conflicts for {0} {1}",getPrimitiveTypeAsString(my), my.id), 
-               ImageProvider.get("data", "object"), 
-               JLabel.HORIZONTAL
-            )
-         );
+                new JLabel(
+                        tr("Resolve version conflicts for {0} {1}",getPrimitiveTypeAsString(my), my.id),
+                        ImageProvider.get("data", "object"),
+                        JLabel.HORIZONTAL
+                )
+        );
     }
 
@@ -66,5 +66,5 @@
         super.executeCommand();
         my.version = Math.max(my.version, their.version);
-        Main.map.conflictDialog.conflicts.remove(my);
+        Main.map.conflictDialog.removeConflictForPrimitive(my);
         return true;
     }
@@ -79,12 +79,12 @@
     public void undoCommand() {
         super.undoCommand();
-        
+
         // restore a conflict if necessary
         //
         if (!Main.map.conflictDialog.conflicts.containsKey(my)) {
-            Main.map.conflictDialog.conflicts.put(my,their);
+            Main.map.conflictDialog.addConflict(my, their);
         }
     }
 
-    
+
 }
Index: /trunk/src/org/openstreetmap/josm/gui/conflict/ConflictResolver.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/conflict/ConflictResolver.java	(revision 1641)
+++ /trunk/src/org/openstreetmap/josm/gui/conflict/ConflictResolver.java	(revision 1642)
@@ -189,6 +189,30 @@
             }
         }
-
         return new SequenceCommand(tr("Conflict Resolution"), commands);
     }
+
+    public boolean isCompletelyResolved() {
+        if (my instanceof Node) {
+            // resolve the version conflict if this is a node and all tag
+            // conflicts have been resolved
+            //
+            if (tagMerger.getModel().isResolvedCompletely())
+                return true;
+        } else if (my instanceof Way) {
+            // resolve the version conflict if this is a way, all tag
+            // conflicts have been resolved, and conflicts in the node list
+            // have been resolved
+            //
+            if (tagMerger.getModel().isResolvedCompletely() && nodeListMerger.getModel().isFrozen())
+                return true;
+        }  else if (my instanceof Relation) {
+            // resolve the version conflict if this is a relation, all tag
+            // conflicts and all conflicts in the member list
+            // have been resolved
+            //
+            if (tagMerger.getModel().isResolvedCompletely() && relationMemberMerger.getModel().isFrozen())
+                return true;
+        }
+        return false;
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/gui/conflict/ListMergeModel.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/conflict/ListMergeModel.java	(revision 1641)
+++ /trunk/src/org/openstreetmap/josm/gui/conflict/ListMergeModel.java	(revision 1642)
@@ -11,5 +11,4 @@
 
 import javax.swing.DefaultListSelectionModel;
-import javax.swing.ListSelectionModel;
 import javax.swing.table.DefaultTableModel;
 import javax.swing.table.TableModel;
@@ -35,5 +34,5 @@
  * {@see #PROP_FROZEN}.
  * 
- * ListMergeModel is an abstract class. There methods have to be implemented by subclasses:
+ * ListMergeModel is an abstract class. Three methods have to be implemented by subclasses:
  * <ul>
  *   <li>{@see ListMergeModel#cloneEntry(Object)} - clones an entry of type T</li>
@@ -61,7 +60,7 @@
     protected DefaultTableModel mergedEntriesTableModel;
 
-    protected DefaultListSelectionModel myEntriesSelectionModel;
-    protected DefaultListSelectionModel theirEntriesSelectionModel;
-    protected DefaultListSelectionModel mergedEntriesSelectionModel;
+    protected EntriesSelectionModel<T> myEntriesSelectionModel;
+    protected EntriesSelectionModel<T> theirEntriesSelectionModel;
+    protected EntriesSelectionModel<T> mergedEntriesSelectionModel;
 
     private final ArrayList<PropertyChangeListener> listeners;
@@ -100,13 +99,13 @@
 
     protected void buildMyEntriesTableModel() {
-        myEntriesTableModel = new ListTableModel<T>(myEntries);
+        myEntriesTableModel = new EntriesTableModel<T>(myEntries);
     }
 
     protected void buildTheirEntriesTableModel() {
-        theirEntriesTableModel = new ListTableModel<T>(theirEntries);
+        theirEntriesTableModel = new EntriesTableModel<T>(theirEntries);
     }
 
     protected void buildMergedEntriesTableModel() {
-        mergedEntriesTableModel = new ListTableModel<T>(mergedEntries);
+        mergedEntriesTableModel = new EntriesTableModel<T>(mergedEntries);
     }
 
@@ -120,7 +119,7 @@
         buildMergedEntriesTableModel();
 
-        myEntriesSelectionModel = new DefaultListSelectionModel();
-        theirEntriesSelectionModel = new DefaultListSelectionModel();
-        mergedEntriesSelectionModel = new DefaultListSelectionModel();
+        myEntriesSelectionModel = new EntriesSelectionModel<T>(myEntries);
+        theirEntriesSelectionModel = new EntriesSelectionModel<T>(theirEntries);
+        mergedEntriesSelectionModel =  new EntriesSelectionModel<T>(mergedEntries);
 
         listeners = new ArrayList<PropertyChangeListener>();
@@ -177,13 +176,13 @@
     }
 
-    public ListSelectionModel getMySelectionModel() {
+    public EntriesSelectionModel getMySelectionModel() {
         return myEntriesSelectionModel;
     }
 
-    public ListSelectionModel getTheirSelectionModel() {
+    public EntriesSelectionModel getTheirSelectionModel() {
         return theirEntriesSelectionModel;
     }
 
-    public ListSelectionModel getMergedSelectionModel() {
+    public EntriesSelectionModel getMergedSelectionModel() {
         return mergedEntriesSelectionModel;
     }
@@ -339,5 +338,9 @@
             throw new IllegalArgumentException(tr("parameter current out of range: got {0}", current));
         if (current == mergedEntries.size() -1) {
-            copyMyToEnd(rows);
+            if (source == myEntries) {
+                copyMyToEnd(rows);
+            } else if (source == theirEntries) {
+                copyTheirToEnd(rows);
+            }
         } else {
             for (int i=rows.length -1; i>=0; i--) {
@@ -461,9 +464,8 @@
 
 
-
-    protected class ListTableModel<T> extends DefaultTableModel {
-        private final ArrayList<T> entries;
-
-        public ListTableModel(ArrayList<T> nodes) {
+    protected class EntriesTableModel<T1> extends DefaultTableModel {
+        private final ArrayList<T1> entries;
+
+        public EntriesTableModel(ArrayList<T1> nodes) {
             this.entries = nodes;
         }
@@ -471,10 +473,15 @@
         @Override
         public int getRowCount() {
-            return entries == null ? 0 : entries.size();
+            int count = myEntries.size();
+            count = Math.max(count, mergedEntries.size());
+            count = Math.max(count, theirEntries.size());
+            return count;
         }
 
         @Override
         public Object getValueAt(int row, int column) {
-            return entries.get(row);
+            if (row < entries.size())
+                return entries.get(row);
+            return null;
         }
 
@@ -490,5 +497,90 @@
     }
 
-
-
+    protected class EntriesSelectionModel<T1> extends DefaultListSelectionModel {
+        private final ArrayList<T1> entries;
+
+        public EntriesSelectionModel(ArrayList<T1> nodes) {
+            this.entries = nodes;
+        }
+
+        @Override
+        public void addSelectionInterval(int index0, int index1) {
+            if (entries.isEmpty()) return;
+            if (index0 > entries.size() - 1) return;
+            index0 = Math.min(entries.size()-1, index0);
+            index1 = Math.min(entries.size()-1, index1);
+            super.addSelectionInterval(index0, index1);
+        }
+
+        @Override
+        public void insertIndexInterval(int index, int length, boolean before) {
+            if (entries.isEmpty()) return;
+            if (before) {
+                int newindex = Math.min(entries.size()-1, index);
+                if (newindex < index - length) return;
+                length = length - (index - newindex);
+                super.insertIndexInterval(newindex, length, before);
+            } else {
+                if (index > entries.size() -1) return;
+                length = Math.min(entries.size()-1 - index, length);
+                super.insertIndexInterval(index, length, before);
+            }
+        }
+
+        @Override
+        public void moveLeadSelectionIndex(int leadIndex) {
+            if (entries.isEmpty()) return;
+            leadIndex = Math.max(0, leadIndex);
+            leadIndex = Math.min(entries.size() - 1, leadIndex);
+            super.moveLeadSelectionIndex(leadIndex);
+        }
+
+        @Override
+        public void removeIndexInterval(int index0, int index1) {
+            if (entries.isEmpty()) return;
+            index0 = Math.max(0, index0);
+            index0 = Math.min(entries.size() - 1, index0);
+
+            index1 = Math.max(0, index1);
+            index1 = Math.min(entries.size() - 1, index1);
+            super.removeIndexInterval(index0, index1);
+        }
+
+        @Override
+        public void removeSelectionInterval(int index0, int index1) {
+            if (entries.isEmpty()) return;
+            index0 = Math.max(0, index0);
+            index0 = Math.min(entries.size() - 1, index0);
+
+            index1 = Math.max(0, index1);
+            index1 = Math.min(entries.size() - 1, index1);
+            super.removeSelectionInterval(index0, index1);
+        }
+
+        @Override
+        public void setAnchorSelectionIndex(int anchorIndex) {
+            if (entries.isEmpty()) return;
+            anchorIndex = Math.min(entries.size() - 1, anchorIndex);
+            super.setAnchorSelectionIndex(anchorIndex);
+        }
+
+        @Override
+        public void setLeadSelectionIndex(int leadIndex) {
+            if (entries.isEmpty()) return;
+            leadIndex = Math.min(entries.size() - 1, leadIndex);
+            super.setLeadSelectionIndex(leadIndex);
+        }
+
+        @Override
+        public void setSelectionInterval(int index0, int index1) {
+            if (entries.isEmpty()) return;
+            index0 = Math.max(0, index0);
+            index0 = Math.min(entries.size() - 1, index0);
+
+            index1 = Math.max(0, index1);
+            index1 = Math.min(entries.size() - 1, index1);
+
+            super.setSelectionInterval(index0, index1);
+        }
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/gui/conflict/ListMerger.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/conflict/ListMerger.java	(revision 1641)
+++ /trunk/src/org/openstreetmap/josm/gui/conflict/ListMerger.java	(revision 1642)
@@ -3,12 +3,20 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
+import java.awt.Adjustable;
+import java.awt.FlowLayout;
 import java.awt.GridBagConstraints;
 import java.awt.GridBagLayout;
 import java.awt.Insets;
 import java.awt.event.ActionEvent;
+import java.awt.event.AdjustmentEvent;
+import java.awt.event.AdjustmentListener;
 import java.awt.event.ItemEvent;
 import java.awt.event.ItemListener;
 import java.beans.PropertyChangeEvent;
 import java.beans.PropertyChangeListener;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Observable;
+import java.util.Observer;
 import java.util.logging.Logger;
 
@@ -17,4 +25,5 @@
 import javax.swing.ImageIcon;
 import javax.swing.JButton;
+import javax.swing.JCheckBox;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
@@ -58,5 +67,13 @@
     private FreezeAction freezeAction;
 
-
+    private AdjustmentSynchronizer adjustmentSynchronizer;
+
+    private  JCheckBox cbLockMyScrolling;
+    private  JCheckBox cbLockMergedScrolling;
+    private  JCheckBox cbLockTheirScrolling;
+
+    abstract protected JScrollPane buildMyElementsTable();
+    abstract protected JScrollPane buildMergedElementsTable();
+    abstract protected JScrollPane buildTheirElementsTable();
 
     protected JScrollPane embeddInScrollPane(JTable table) {
@@ -64,12 +81,9 @@
         pane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
         pane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
+        if (adjustmentSynchronizer == null) {
+            adjustmentSynchronizer = new AdjustmentSynchronizer();
+        }
         return pane;
     }
-
-    abstract protected JScrollPane buildMyElementsTable();
-    abstract protected JScrollPane buildMergedElementsTable();
-    abstract protected JScrollPane buildTheirElementsTable();
-
-
 
     protected void wireActionsToSelectionModels() {
@@ -99,6 +113,4 @@
         mergedEntriesTable.getSelectionModel().addListSelectionListener(removeMergedAction);
     }
-
-
 
     protected JPanel buildLeftButtonPanel() {
@@ -206,8 +218,17 @@
     }
 
+    protected JPanel buildAdjustmentLockControlPanel(JCheckBox cb) {
+        JPanel panel = new JPanel();
+        panel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+        panel.add(new JLabel(tr("lock scrolling")));
+        panel.add(cb);
+        return panel;
+    }
+
     protected void build() {
         setLayout(new GridBagLayout());
         GridBagConstraints gc = new GridBagConstraints();
 
+        // ------------------
         gc.gridx = 0;
         gc.gridy = 0;
@@ -225,10 +246,4 @@
         gc.gridx = 2;
         gc.gridy = 0;
-        gc.gridwidth = 1;
-        gc.gridheight = 1;
-        gc.fill = GridBagConstraints.NONE;
-        gc.anchor = GridBagConstraints.CENTER;
-        gc.weightx = 0.0;
-        gc.weighty = 0.0;
         lbl = new JLabel(tr("Merged version"));
         lbl.setToolTipText(tr("List of merged elements. They will replace the my elements when the merge decisions are applied."));
@@ -237,30 +252,50 @@
         gc.gridx = 4;
         gc.gridy = 0;
+        lbl = new JLabel(tr("Their version"));
+        lbl.setToolTipText(tr("List of elements in their dataset, i.e. the server dataset"));
+        add(lbl, gc);
+
+        // ------------------------------
+        gc.gridx = 0;
+        gc.gridy = 1;
         gc.gridwidth = 1;
         gc.gridheight = 1;
-        gc.fill = GridBagConstraints.NONE;
-        gc.anchor = GridBagConstraints.CENTER;
-        gc.weightx = 0.0;
+        gc.fill = GridBagConstraints.HORIZONTAL;
+        gc.anchor = GridBagConstraints.FIRST_LINE_START;
+        gc.weightx = 0.33;
         gc.weighty = 0.0;
-        lbl = new JLabel(tr("Their version"));
-        lbl.setToolTipText(tr("List of elements in their dataset, i.e. the server dataset"));
-
-        add(lbl, gc);
-
-        gc.gridx = 0;
+        gc.insets = new Insets(0,0,0,0);
+        cbLockMyScrolling = new JCheckBox();
+        cbLockMyScrolling.setName("checkbox.lockmyscrolling");
+        add(buildAdjustmentLockControlPanel(cbLockMyScrolling), gc);
+
+        gc.gridx = 2;
         gc.gridy = 1;
+        cbLockMergedScrolling = new JCheckBox();
+        cbLockMergedScrolling.setName("checkbox.lockmergedscrolling");
+        add(buildAdjustmentLockControlPanel(cbLockMergedScrolling), gc);
+
+        gc.gridx = 4;
+        gc.gridy = 1;
+        cbLockTheirScrolling = new JCheckBox();
+        cbLockTheirScrolling.setName("checkbox.locktheirscrolling");
+        add(buildAdjustmentLockControlPanel(cbLockTheirScrolling), gc);
+
+        // --------------------------------
+        gc.gridx = 0;
+        gc.gridy = 2;
         gc.gridwidth = 1;
         gc.gridheight = 1;
         gc.fill = GridBagConstraints.BOTH;
         gc.anchor = GridBagConstraints.FIRST_LINE_START;
-        gc.weightx = 0.3;
+        gc.weightx = 0.33;
         gc.weighty = 1.0;
         gc.insets = new Insets(0,0,0,0);
-        add(buildMyElementsTable(), gc);
+        JScrollPane pane = buildMyElementsTable();
+        adjustmentSynchronizer.adapt(cbLockMyScrolling, pane.getVerticalScrollBar());
+        add(pane, gc);
 
         gc.gridx = 1;
-        gc.gridy = 1;
-        gc.gridwidth = 1;
-        gc.gridheight = 1;
+        gc.gridy = 2;
         gc.fill = GridBagConstraints.NONE;
         gc.anchor = GridBagConstraints.CENTER;
@@ -270,17 +305,15 @@
 
         gc.gridx = 2;
-        gc.gridy = 1;
-        gc.gridwidth = 1;
-        gc.gridheight = 1;
+        gc.gridy = 2;
         gc.fill = GridBagConstraints.BOTH;
         gc.anchor = GridBagConstraints.FIRST_LINE_START;
-        gc.weightx = 0.3;
+        gc.weightx = 0.33;
         gc.weighty = 0.0;
-        add(buildMergedElementsTable(), gc);
+        pane = buildMergedElementsTable();
+        adjustmentSynchronizer.adapt(cbLockMergedScrolling, pane.getVerticalScrollBar());
+        add(pane, gc);
 
         gc.gridx = 3;
-        gc.gridy = 1;
-        gc.gridwidth = 1;
-        gc.gridheight = 1;
+        gc.gridy = 2;
         gc.fill = GridBagConstraints.NONE;
         gc.anchor = GridBagConstraints.CENTER;
@@ -290,20 +323,21 @@
 
         gc.gridx = 4;
-        gc.gridy = 1;
-        gc.gridwidth = 1;
-        gc.gridheight = 1;
+        gc.gridy = 2;
         gc.fill = GridBagConstraints.BOTH;
         gc.anchor = GridBagConstraints.FIRST_LINE_START;
-        gc.weightx = 0.3;
+        gc.weightx = 0.33;
         gc.weighty = 0.0;
-        add(buildTheirElementsTable(), gc);
-
+        pane = buildTheirElementsTable();
+        adjustmentSynchronizer.adapt(cbLockTheirScrolling, pane.getVerticalScrollBar());
+        add(pane, gc);
+
+        // ----------------------------------
         gc.gridx = 2;
-        gc.gridy = 2;
+        gc.gridy = 3;
         gc.gridwidth = 1;
         gc.gridheight = 1;
         gc.fill = GridBagConstraints.BOTH;
         gc.anchor = GridBagConstraints.CENTER;
-        gc.weightx = 0.3;
+        gc.weightx = 0.0;
         gc.weighty = 0.0;
         add(buildMergedListControlButtons(), gc);
@@ -317,5 +351,4 @@
         model.addPropertyChangeListener(this);
     }
-
 
     /**
@@ -666,15 +699,4 @@
          */
         public void adapt(final JToggleButton btn) {
-            //            btn.addItemListener(
-            //                    new ItemListener() {
-            //                        public void itemStateChanged(ItemEvent e) {
-            //                            boolean isSelected = (Boolean)getValue(PROP_SELECTED);
-            //                            if (isSelected != (e.getStateChange() == ItemEvent.SELECTED)) {
-            //                                putValue(PROP_SELECTED, e.getStateChange() == ItemEvent.SELECTED);
-            //                            }
-            //                            model.setFrozen(e.getStateChange() == ItemEvent.SELECTED);
-            //                        }
-            //                    }
-            //            );
             btn.addItemListener(this);
             addPropertyChangeListener(
@@ -728,3 +750,148 @@
         return model;
     }
+
+
+
+    /**
+     * Synchronizes scrollbar adjustments between a set of
+     * {@see Adjustable}s. Whenever the adjustment of one of
+     * the registerd Adjustables is updated the adjustment of
+     * the other registered Adjustables is adjusted too.
+     * 
+     */
+    class AdjustmentSynchronizer implements AdjustmentListener {
+
+        private final  ArrayList<Adjustable> synchronizedAdjustables;
+        private final  HashMap<Adjustable, Boolean> enabledMap;
+
+        private final Observable observable;
+
+        public AdjustmentSynchronizer() {
+            synchronizedAdjustables = new ArrayList<Adjustable>();
+            enabledMap = new HashMap<Adjustable, Boolean>();
+            observable = new Observable();
+        }
+
+
+        /**
+         * registers an {@see Adjustable} for participation in synchronized
+         * scrolling.
+         * 
+         * @param adjustable the adjustable
+         */
+        public void participateInSynchronizedScrolling(Adjustable adjustable) {
+            if (adjustable == null)
+                return;
+            if (synchronizedAdjustables.contains(adjustable))
+                return;
+            synchronizedAdjustables.add(adjustable);
+            setParticipatingInSynchronizedScrolling(adjustable, true);
+            adjustable.addAdjustmentListener(this);
+        }
+
+        /**
+         * event handler for {@see AdjustmentEvent}s
+         * 
+         */
+        public void adjustmentValueChanged(AdjustmentEvent e) {
+            if (! enabledMap.get(e.getAdjustable()))
+                return;
+            for (Adjustable a : synchronizedAdjustables) {
+                if (a != e.getAdjustable() && isParticipatingInSynchronizedScrolling(a)) {
+                    a.setValue(e.getValue());
+                }
+            }
+        }
+
+        /**
+         * sets whether adjustable participates in adjustment synchronization
+         * or not
+         * 
+         * @param adjustable the adjustable
+         */
+        protected void setParticipatingInSynchronizedScrolling(Adjustable adjustable, boolean isParticipating) {
+            if (adjustable == null)
+                throw new IllegalArgumentException(tr("argument \"adjustable\" must not be null"));
+
+            if (! synchronizedAdjustables.contains(adjustable))
+                throw new IllegalStateException(tr("adjustable {0} not registered yet. Can't set participation in synchronized adjustment",adjustable));
+
+            enabledMap.put(adjustable, isParticipating);
+            observable.notifyObservers();
+        }
+
+        /**
+         * returns true if an adjustable is participating in synchronized scrolling
+         * 
+         * @param adjustable the adjustable
+         * @return true, if the adjustable is participating in synchronized scrolling, false otherwise
+         * @throws IllegalStateException thrown, if adjustable is not registered for synchronized scrolling
+         */
+        protected boolean isParticipatingInSynchronizedScrolling(Adjustable adjustable) throws IllegalStateException {
+            if (! synchronizedAdjustables.contains(adjustable))
+                throw new IllegalStateException(tr("adjustable {0} not registered yet",adjustable));
+
+            return enabledMap.get(adjustable);
+        }
+
+        /**
+         * wires a {@see JCheckBox} to  the adjustment synchronizer, in such a way  that:
+         * <li>
+         *   <ol>state changes in the checkbox control whether the adjustable participates
+         *      in synchronized adjustment</ol>
+         *   <ol>state changes in this {@see AdjustmentSynchronizer} are reflected in the
+         *      {@see JCheckBox}</ol>
+         * </li>
+         * 
+         * 
+         * @param view  the checkbox to control whether an adjustable participates in synchronized
+         *      adjustment
+         * @param adjustable the adjustable
+         * @exception IllegalArgumentException thrown, if view is null
+         * @exception IllegalArgumentException thrown, if adjustable is null
+         */
+        protected void adapt(final JCheckBox view, final Adjustable adjustable) throws IllegalArgumentException, IllegalStateException {
+            if (adjustable == null)
+                throw new IllegalArgumentException(tr("argument \"adjustable\" must not be null"));
+            if (view == null)
+                throw new IllegalArgumentException(tr("argument \"view\" must not be null"));
+
+            if (! synchronizedAdjustables.contains(adjustable)) {
+                participateInSynchronizedScrolling(adjustable);
+            }
+
+            // register an item lister with the check box
+            //
+            view.addItemListener(new ItemListener() {
+                public void itemStateChanged(ItemEvent e) {
+                    switch(e.getStateChange()) {
+                    case ItemEvent.SELECTED:
+                        if (!isParticipatingInSynchronizedScrolling(adjustable)) {
+                            setParticipatingInSynchronizedScrolling(adjustable, true);
+                        }
+                        break;
+                    case ItemEvent.DESELECTED:
+                        if (isParticipatingInSynchronizedScrolling(adjustable)) {
+                            setParticipatingInSynchronizedScrolling(adjustable, false);
+                        }
+                        break;
+                    }
+                }
+            });
+
+
+            observable.addObserver(
+                    new Observer() {
+                        public void update(Observable o, Object arg) {
+                            boolean sync = isParticipatingInSynchronizedScrolling(adjustable);
+                            if (view.isSelected() != sync) {
+                                view.setSelected(sync);
+                            }
+                        }
+                    }
+            );
+            setParticipatingInSynchronizedScrolling(adjustable, true);
+            view.setSelected(true);
+        }
+    }
 }
Index: /trunk/src/org/openstreetmap/josm/gui/conflict/nodes/NodeListColumnModel.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/conflict/nodes/NodeListColumnModel.java	(revision 1641)
+++ /trunk/src/org/openstreetmap/josm/gui/conflict/nodes/NodeListColumnModel.java	(revision 1642)
@@ -14,6 +14,15 @@
         TableColumn col = null;
 
-        // column 0 - Node
+        // column 0 - Row num
         col = new TableColumn(0);
+        col.setHeaderValue("");
+        col.setResizable(false);
+        col.setWidth(30);
+        col.setMaxWidth(30);
+        col.setCellRenderer(renderer);
+        addColumn(col);
+
+        // column 1 - Node
+        col = new TableColumn(1);
         col.setHeaderValue(tr("Node"));
         col.setResizable(true);
Index: /trunk/src/org/openstreetmap/josm/gui/conflict/nodes/NodeListMerger.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/conflict/nodes/NodeListMerger.java	(revision 1641)
+++ /trunk/src/org/openstreetmap/josm/gui/conflict/nodes/NodeListMerger.java	(revision 1642)
@@ -32,4 +32,5 @@
         );
         myEntriesTable.setName("table.mynodes");
+        myEntriesTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
         return embeddInScrollPane(myEntriesTable);
     }
@@ -45,4 +46,5 @@
         );
         mergedEntriesTable.setName("table.mergednodes");
+        mergedEntriesTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
         return embeddInScrollPane(mergedEntriesTable);
     }
@@ -58,4 +60,5 @@
         );
         theirEntriesTable.setName("table.theirnodes");
+        theirEntriesTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
         return embeddInScrollPane(theirEntriesTable);
     }
Index: /trunk/src/org/openstreetmap/josm/gui/conflict/nodes/NodeListTableCellRenderer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/conflict/nodes/NodeListTableCellRenderer.java	(revision 1641)
+++ /trunk/src/org/openstreetmap/josm/gui/conflict/nodes/NodeListTableCellRenderer.java	(revision 1642)
@@ -6,36 +6,27 @@
 import java.awt.Color;
 import java.awt.Component;
-import java.net.URL;
 import java.text.DecimalFormat;
 
+import javax.swing.BorderFactory;
 import javax.swing.ImageIcon;
 import javax.swing.JLabel;
 import javax.swing.JTable;
+import javax.swing.border.Border;
 import javax.swing.table.TableCellRenderer;
 
 import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.tools.ImageProvider;
 
 /**
  * This is the {@see TableCellRenderer} used in the node tables of {@see NodeListMerger}.
  * 
- *
  */
 public  class NodeListTableCellRenderer extends JLabel implements TableCellRenderer {
     private static DecimalFormat COORD_FORMATTER = new DecimalFormat("###0.0000");
     public final static Color BGCOLOR_SELECTED = new Color(143,170,255);
+    public final static Color BGCOLOR_EMPTY_ROW = new Color(234,234,234);
 
-    /**
-     * Load the image icon for an OSM primitive of type node
-     * 
-     * @return the icon; null, if not found
-     */
-    protected ImageIcon loadIcon() {
-        URL url = this.getClass().getResource("/images/data/node.png");;
-        if (url == null) {
-            System.out.println(tr("Failed to load resource /images/data/node.png"));
-            return null;
-        }
-        return new ImageIcon(url);
-    }
+    private ImageIcon icon = null;
+    private Border rowNumberBorder = null;
 
     /**
@@ -43,5 +34,6 @@
      */
     public NodeListTableCellRenderer() {
-        setIcon(loadIcon());
+        icon = ImageProvider.get("data", "node");
+        rowNumberBorder = BorderFactory.createEmptyBorder(0,4,0,0);
         setOpaque(true);
     }
@@ -90,8 +82,30 @@
      */
     protected  void renderNode(Node node, boolean isSelected) {
+        setIcon(icon);
+        setBorder(null);
         if (isSelected) {
             setBackground(BGCOLOR_SELECTED);
         }
         setText(getDisplayName(node));
+    }
+
+    protected void renderEmptyRow() {
+        setIcon(null);
+        setBackground(BGCOLOR_EMPTY_ROW);
+        setText("");
+    }
+
+    /**
+     * render the row id
+     * @param row the row index
+     * @param isSelected
+     */
+    protected  void renderRowId(int row, boolean isSelected) {
+        setIcon(null);
+        setBorder(rowNumberBorder);
+        if (isSelected) {
+            setBackground(BGCOLOR_SELECTED);
+        }
+        setText(Integer.toString(row+1));
     }
 
@@ -101,5 +115,19 @@
         Node node = (Node)value;
         reset();
-        renderNode(node,isSelected);
+        switch(column) {
+        case 0:
+            renderRowId(row, isSelected);
+            break;
+        case 1:
+            if (node == null) {
+                renderEmptyRow();
+            } else {
+                renderNode(node,isSelected);
+            }
+            break;
+        default:
+            // should not happen
+            throw new RuntimeException(tr("unexpected column index. Got {0}", column));
+        }
         return this;
     }
Index: /trunk/src/org/openstreetmap/josm/gui/conflict/relation/RelationMemberListColumnModel.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/conflict/relation/RelationMemberListColumnModel.java	(revision 1641)
+++ /trunk/src/org/openstreetmap/josm/gui/conflict/relation/RelationMemberListColumnModel.java	(revision 1642)
@@ -15,12 +15,22 @@
         // column 0 - Role
         col = new TableColumn(0);
+        col.setHeaderValue("");
+        col.setResizable(false);
+        col.setWidth(20);
+        col.setMaxWidth(20);
+        col.setCellRenderer(renderer);
+        addColumn(col);
+
+        // column 1 - Role
+        col = new TableColumn(1);
         col.setHeaderValue(tr("Role"));
         col.setResizable(true);
         col.setCellRenderer(renderer);
+        col.setMaxWidth(100);
         col.setCellEditor(new RelationMemberTableCellEditor());
         addColumn(col);
 
-        // column 1 - Primitive
-        col = new TableColumn(1);
+        // column 2 - Primitive
+        col = new TableColumn(2);
         col.setHeaderValue(tr("Primitive"));
         col.setResizable(true);
Index: /trunk/src/org/openstreetmap/josm/gui/conflict/relation/RelationMemberListMergeModel.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/conflict/relation/RelationMemberListMergeModel.java	(revision 1641)
+++ /trunk/src/org/openstreetmap/josm/gui/conflict/relation/RelationMemberListMergeModel.java	(revision 1642)
@@ -37,9 +37,9 @@
         // editing cells in the first column
         //
-        mergedEntriesTableModel = this.new ListTableModel<RelationMember>(mergedEntries) {
+        mergedEntriesTableModel = this.new EntriesTableModel<RelationMember>(mergedEntries) {
             @Override
             public boolean isCellEditable(int row, int column) {
                 switch(column) {
-                case 0: return true;
+                case 1: return true;
                 default: return false;
                 }
@@ -50,5 +50,5 @@
     @Override
     protected void setValueAt(DefaultTableModel model, Object value, int row, int col) {
-        if (model == getMergedTableModel() && col == 0) {
+        if (model == getMergedTableModel() && col == 1) {
             RelationMember member = mergedEntries.get(row);
             member.role = (String)value;
Index: /trunk/src/org/openstreetmap/josm/gui/conflict/relation/RelationMemberMerger.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/conflict/relation/RelationMemberMerger.java	(revision 1641)
+++ /trunk/src/org/openstreetmap/josm/gui/conflict/relation/RelationMemberMerger.java	(revision 1642)
@@ -25,4 +25,5 @@
         );
         myEntriesTable.setName("table.mynodes");
+        myEntriesTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
         return embeddInScrollPane(myEntriesTable);
     }
@@ -30,5 +31,4 @@
     @Override
     protected JScrollPane buildMergedElementsTable() {
-        logger.info(model.getMergedTableModel().toString());
         mergedEntriesTable  = new JTable(
                 model.getMergedTableModel(),
@@ -38,4 +38,5 @@
         mergedEntriesTable.putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
         mergedEntriesTable.setName("table.mergednodes");
+        mergedEntriesTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
         return embeddInScrollPane(mergedEntriesTable);
     }
@@ -49,4 +50,5 @@
         );
         theirEntriesTable.setName("table.theirnodes");
+        theirEntriesTable.setAutoResizeMode(JTable.AUTO_RESIZE_LAST_COLUMN);
         return embeddInScrollPane(theirEntriesTable);
     }
Index: /trunk/src/org/openstreetmap/josm/gui/conflict/relation/RelationMemberTableCellRenderer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/conflict/relation/RelationMemberTableCellRenderer.java	(revision 1641)
+++ /trunk/src/org/openstreetmap/josm/gui/conflict/relation/RelationMemberTableCellRenderer.java	(revision 1642)
@@ -8,7 +8,9 @@
 import java.text.DecimalFormat;
 
+import javax.swing.BorderFactory;
 import javax.swing.ImageIcon;
 import javax.swing.JLabel;
 import javax.swing.JTable;
+import javax.swing.border.Border;
 import javax.swing.table.TableCellRenderer;
 
@@ -23,13 +25,14 @@
  * This is the {@see TableCellRenderer} used in the tables of {@see RelationMemberMerger}.
  * 
- *
  */
 public  class RelationMemberTableCellRenderer extends JLabel implements TableCellRenderer {
-    private static DecimalFormat COORD_FORMATTER = new DecimalFormat("###0.0000");
+    private final static DecimalFormat COORD_FORMATTER = new DecimalFormat("###0.0000");
     public final static Color BGCOLOR_SELECTED = new Color(143,170,255);
+    public final static Color BGCOLOR_EMPTY_ROW = new Color(234,234,234);
 
     private ImageIcon nodeIcon;
     private ImageIcon wayIcon;
     private ImageIcon relationIcon;
+    private  Border rowNumberBorder = null;
 
     /**
@@ -51,4 +54,5 @@
         setOpaque(true);
         loadIcons();
+        rowNumberBorder = BorderFactory.createEmptyBorder(0,4,0,0);
     }
 
@@ -100,4 +104,7 @@
         setBackground(Color.WHITE);
         setForeground(Color.BLACK);
+        setBorder(null);
+        setIcon(null);
+        setToolTipText(null);
     }
 
@@ -110,5 +117,5 @@
     protected void renderRole(RelationMember member) {
         setText(member.role == null ? "" : member.role);
-        setIcon(null);
+        setToolTipText(member.role == null ? "" : member.role);
     }
 
@@ -129,4 +136,21 @@
     }
 
+    /**
+     * render the row id
+     * @param row the row index
+     * @param isSelected
+     */
+    protected  void renderRowId(int row, boolean isSelected) {
+        setBorder(rowNumberBorder);
+        setText(Integer.toString(row+1));
+    }
+
+    protected void renderEmptyRow() {
+        setIcon(null);
+        setBackground(BGCOLOR_EMPTY_ROW);
+        setText("");
+    }
+
+
     public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
             int row, int column) {
@@ -137,8 +161,19 @@
         switch(column) {
         case 0:
-            renderRole(member);
+            renderRowId(row, isSelected);
             break;
         case 1:
-            renderPrimitive(member);
+            if (member == null) {
+                renderEmptyRow();
+            } else {
+                renderRole(member);
+            }
+            break;
+        case 2:
+            if (member == null) {
+                renderEmptyRow();
+            } else {
+                renderPrimitive(member);
+            }
             break;
         default:
Index: /trunk/src/org/openstreetmap/josm/gui/conflict/tags/MergedTableCellRenderer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/conflict/tags/MergedTableCellRenderer.java	(revision 1642)
+++ /trunk/src/org/openstreetmap/josm/gui/conflict/tags/MergedTableCellRenderer.java	(revision 1642)
@@ -0,0 +1,72 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.conflict.tags;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Color;
+
+public class MergedTableCellRenderer extends TagMergeTableCellRenderer {
+
+    public final static Color BGCOLOR_UNDECIDED = new Color(255,197,197);
+    public final static Color BGCOLOR_MINE = new Color(217,255,217);
+    public final static Color BGCOLOR_THEIR = new Color(217,255,217);
+    public final static Color BGCOLOR_SELECTED = new Color(143,170,255);
+
+    
+    protected void setBackgroundColor(TagMergeItem item, boolean isSelected) {
+        if (isSelected) {
+            setBackground(BGCOLOR_SELECTED);
+            return;
+        }
+        if (MergeDecisionType.KEEP_MINE.equals(item.getMergeDecision())) {
+            setBackground(BGCOLOR_MINE);
+        } else if (MergeDecisionType.KEEP_THEIR.equals(item.getMergeDecision())) {
+            setBackground(BGCOLOR_THEIR); 
+        } else if (MergeDecisionType.UNDECIDED.equals(item.getMergeDecision())) {
+            setBackground(BGCOLOR_UNDECIDED);
+        }        
+    }
+    
+    
+    @Override
+    protected void renderKey(TagMergeItem item, boolean isSelected) {
+        setBackgroundColor(item,isSelected);
+        if (MergeDecisionType.KEEP_MINE.equals(item.getMergeDecision()) && item.getMyTagValue() == null) {
+            setText(tr("<undefined>"));
+            setToolTipText(tr("The merged dataset will not include a tag with key {0}", item.getKey()));
+        } else if (MergeDecisionType.KEEP_THEIR.equals(item.getMergeDecision()) && item.getTheirTagValue() == null) {
+            setText(tr("<undefined>"));
+            setToolTipText(tr("The merged dataset will not include a tag with key {0}", item.getKey()));
+        } else if (MergeDecisionType.UNDECIDED.equals(item.getMergeDecision())) {
+            setText("");
+        } else {
+            setText(item.getKey());
+            setToolTipText(item.getKey());
+        }
+    }
+
+    @Override
+    protected void renderValue(TagMergeItem item, boolean isSelected) {
+        setBackgroundColor(item,isSelected);
+        if (MergeDecisionType.KEEP_MINE.equals(item.getMergeDecision()) && item.getMyTagValue() == null) {
+            setText(tr("<undefined>"));
+            setToolTipText(tr("The merged dataset will not include a tag with key {0}", item.getKey()));
+        } else if (MergeDecisionType.KEEP_THEIR.equals(item.getMergeDecision()) && item.getTheirTagValue() == null) {
+            setText(tr("<undefined>"));
+            setToolTipText(tr("The merged dataset will not include a tag with key {0}", item.getKey()));
+        } else if (MergeDecisionType.UNDECIDED.equals(item.getMergeDecision())) {
+            setText("");
+        } else {
+            if (MergeDecisionType.KEEP_MINE.equals(item.getMergeDecision())) {
+                setText(item.getMyTagValue());
+                setToolTipText(item.getMyTagValue());
+            } else if (MergeDecisionType.KEEP_THEIR.equals(item.getMergeDecision())) {
+                setText(item.getTheirTagValue());
+                setToolTipText(item.getTheirTagValue());
+            } else {
+                // should not happen 
+            }
+        }
+    }
+
+}
Index: /trunk/src/org/openstreetmap/josm/gui/conflict/tags/TagMerger.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/conflict/tags/TagMerger.java	(revision 1641)
+++ /trunk/src/org/openstreetmap/josm/gui/conflict/tags/TagMerger.java	(revision 1642)
@@ -13,5 +13,4 @@
 import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
-import java.net.URL;
 import java.util.ArrayList;
 
@@ -27,4 +26,9 @@
 import javax.swing.event.ListSelectionListener;
 
+import org.openstreetmap.josm.tools.ImageProvider;
+/**
+ * UI component for resolving conflicts in the tag sets of two {@see OsmPrimitive}s.
+ *
+ */
 public class TagMerger extends JPanel {
 
@@ -37,4 +41,10 @@
     AdjustmentSynchronizer adjustmentSynchronizer;
 
+    /**
+     * embeds table in a new {@see JScrollPane} and returns th scroll pane
+     * 
+     * @param table the table
+     * @return the scroll pane embedding the table
+     */
     protected JScrollPane embeddInScrollPane(JTable table) {
         JScrollPane pane = new JScrollPane(table);
@@ -46,4 +56,9 @@
     }
 
+    /**
+     * builds the table for my tag set (table already embedded in a scroll pane)
+     * 
+     * @return the table (embedded in a scroll pane)
+     */
     protected JScrollPane buildMineTagTable() {
         mineTable  = new JTable(
@@ -57,4 +72,9 @@
     }
 
+    /**
+     * builds the table for their tag set (table already embedded in a scroll pane)
+     * 
+     * @return the table (embedded in a scroll pane)
+     */
     protected JScrollPane buildTheirTable() {
         theirTable  = new JTable(
@@ -68,9 +88,15 @@
     }
 
-    protected JScrollPane buildUndecidedTable() {
+    /**
+     * builds the table for the merged tag set (table already embedded in a scroll pane)
+     * 
+     * @return the table (embedded in a scroll pane)
+     */
+
+    protected JScrollPane buildMergedTable() {
         mergedTable  = new JTable(
                 model,
                 new TagMergeColumnModel(
-                        new UndecidedTableCellRenderer()
+                        new MergedTableCellRenderer()
                 )
         );
@@ -79,4 +105,7 @@
     }
 
+    /**
+     * build the user interface
+     */
     protected void build() {
         GridBagConstraints gc = new GridBagConstraints();
@@ -152,5 +181,5 @@
         gc.weightx = 0.3;
         gc.weighty = 1.0;
-        add(buildUndecidedTable(), gc);
+        add(buildMergedTable(), gc);
 
         gc.gridx = 3;
@@ -205,23 +234,20 @@
     }
 
+    /**
+     * replies the model used by this tag merger
+     * 
+     * @return the model
+     */
     public TagMergeModel getModel() {
         return model;
     }
 
-    protected ImageIcon loadIcon(String name) {
-        String path = "/images/dialogs/conflict/" + name;
-        URL url = this.getClass().getResource(path);
-        if (url == null) {
-            System.out.println(tr("WARNING: failed to load resource {0}", path));
-            return null;
-        }
-        return new ImageIcon(url);
-    }
-
+    /**
+     * Keeps the currently selected tags in my table in the list of merged tags.
+     *
+     */
     class KeepMineAction extends AbstractAction implements ListSelectionListener {
-
-
         public KeepMineAction() {
-            ImageIcon icon = loadIcon("tagkeepmine.png");
+            ImageIcon icon = ImageProvider.get("dialogs/conflict", "tagkeepmine.png");
             if (icon != null) {
                 putValue(Action.SMALL_ICON, icon);
@@ -246,8 +272,11 @@
     }
 
+    /**
+     * Keeps the currently selected tags in their table in the list of merged tags.
+     *
+     */
     class KeepTheirAction extends AbstractAction implements ListSelectionListener {
-
         public KeepTheirAction() {
-            ImageIcon icon = loadIcon("tagkeeptheir.png");
+            ImageIcon icon = ImageProvider.get("dialogs/conflict", "tagkeeptheir.png");
             if (icon != null) {
                 putValue(Action.SMALL_ICON, icon);
@@ -272,4 +301,11 @@
     }
 
+    /**
+     * Synchronizes scrollbar adjustments between a set of
+     * {@see Adjustable}s. Whenever the adjustment of one of
+     * the registerd Adjustables is updated the adjustment of
+     * the other registered Adjustables is adjusted too.
+     * 
+     */
     class AdjustmentSynchronizer implements AdjustmentListener {
         private final ArrayList<Adjustable> synchronizedAdjustables;
@@ -297,4 +333,8 @@
     }
 
+    /**
+     * Handler for double clicks on entries in the three tag tables.
+     * 
+     */
     class DoubleClickAdapter extends MouseAdapter {
 
@@ -324,8 +364,13 @@
     }
 
+    /**
+     * Sets the currently selected tags in the table of merged tags to state
+     * {@see MergeDecisionType#UNDECIDED}
+     * 
+     */
     class UndecideAction extends AbstractAction implements ListSelectionListener  {
 
         public UndecideAction() {
-            ImageIcon icon = loadIcon("tagundecide.png");
+            ImageIcon icon = ImageProvider.get("dialogs/conflict", "tagundecide.png");
             if (icon != null) {
                 putValue(Action.SMALL_ICON, icon);
Index: unk/src/org/openstreetmap/josm/gui/conflict/tags/UndecidedTableCellRenderer.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/conflict/tags/UndecidedTableCellRenderer.java	(revision 1641)
+++ 	(revision )
@@ -1,72 +1,0 @@
-// License: GPL. For details, see LICENSE file.
-package org.openstreetmap.josm.gui.conflict.tags;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.Color;
-
-public class UndecidedTableCellRenderer extends TagMergeTableCellRenderer {
-
-    public final static Color BGCOLOR_UNDECIDED = new Color(255,197,197);
-    public final static Color BGCOLOR_MINE = new Color(217,255,217);
-    public final static Color BGCOLOR_THEIR = new Color(217,255,217);
-    public final static Color BGCOLOR_SELECTED = new Color(143,170,255);
-
-    
-    protected void setBackgroundColor(TagMergeItem item, boolean isSelected) {
-        if (isSelected) {
-            setBackground(BGCOLOR_SELECTED);
-            return;
-        }
-        if (MergeDecisionType.KEEP_MINE.equals(item.getMergeDecision())) {
-            setBackground(BGCOLOR_MINE);
-        } else if (MergeDecisionType.KEEP_THEIR.equals(item.getMergeDecision())) {
-            setBackground(BGCOLOR_THEIR); 
-        } else if (MergeDecisionType.UNDECIDED.equals(item.getMergeDecision())) {
-            setBackground(BGCOLOR_UNDECIDED);
-        }        
-    }
-    
-    
-    @Override
-    protected void renderKey(TagMergeItem item, boolean isSelected) {
-        setBackgroundColor(item,isSelected);
-        if (MergeDecisionType.KEEP_MINE.equals(item.getMergeDecision()) && item.getMyTagValue() == null) {
-            setText(tr("<undefined>"));
-            setToolTipText(tr("The merged dataset will not include a tag with key {0}", item.getKey()));
-        } else if (MergeDecisionType.KEEP_THEIR.equals(item.getMergeDecision()) && item.getTheirTagValue() == null) {
-            setText(tr("<undefined>"));
-            setToolTipText(tr("The merged dataset will not include a tag with key {0}", item.getKey()));
-        } else if (MergeDecisionType.UNDECIDED.equals(item.getMergeDecision())) {
-            setText("");
-        } else {
-            setText(item.getKey());
-            setToolTipText(item.getKey());
-        }
-    }
-
-    @Override
-    protected void renderValue(TagMergeItem item, boolean isSelected) {
-        setBackgroundColor(item,isSelected);
-        if (MergeDecisionType.KEEP_MINE.equals(item.getMergeDecision()) && item.getMyTagValue() == null) {
-            setText(tr("<undefined>"));
-            setToolTipText(tr("The merged dataset will not include a tag with key {0}", item.getKey()));
-        } else if (MergeDecisionType.KEEP_THEIR.equals(item.getMergeDecision()) && item.getTheirTagValue() == null) {
-            setText(tr("<undefined>"));
-            setToolTipText(tr("The merged dataset will not include a tag with key {0}", item.getKey()));
-        } else if (MergeDecisionType.UNDECIDED.equals(item.getMergeDecision())) {
-            setText("");
-        } else {
-            if (MergeDecisionType.KEEP_MINE.equals(item.getMergeDecision())) {
-                setText(item.getMyTagValue());
-                setToolTipText(item.getMyTagValue());
-            } else if (MergeDecisionType.KEEP_THEIR.equals(item.getMergeDecision())) {
-                setText(item.getTheirTagValue());
-                setToolTipText(item.getTheirTagValue());
-            } else {
-                // should not happen 
-            }
-        }
-    }
-
-}
Index: /trunk/src/org/openstreetmap/josm/gui/dialogs/ConflictDialog.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/dialogs/ConflictDialog.java	(revision 1641)
+++ /trunk/src/org/openstreetmap/josm/gui/dialogs/ConflictDialog.java	(revision 1642)
@@ -51,14 +51,15 @@
     private final DefaultListModel model = new DefaultListModel();
     private final JList displaylist = new JList(model);
-    
+
     private final SideButton sbSelect = new SideButton(marktr("Select"), "select", "Conflict",
             tr("Set the selected elements on the map to the selected items in the list above."), new ActionListener(){
-                public void actionPerformed(ActionEvent e) {
-                    Collection<OsmPrimitive> sel = new LinkedList<OsmPrimitive>();
-                    for (Object o : displaylist.getSelectedValues())
-                        sel.add((OsmPrimitive)o);
-                    Main.ds.setSelected(sel);
-                }
-            });
+        public void actionPerformed(ActionEvent e) {
+            Collection<OsmPrimitive> sel = new LinkedList<OsmPrimitive>();
+            for (Object o : displaylist.getSelectedValues()) {
+                sel.add((OsmPrimitive)o);
+            }
+            Main.ds.setSelected(sel);
+        }
+    });
     private final SideButton sbResolve = new SideButton(marktr("Resolve"), "conflict", "Conflict",
             tr("Open a merge dialog of all selected items in the list above."), new ActionListener(){
@@ -70,11 +71,12 @@
     public ConflictDialog() {
         super(tr("Conflict"), "conflict", tr("Merging conflicts."),
-        Shortcut.registerShortcut("subwindow:conflict", tr("Toggle: {0}", tr("Conflict")), KeyEvent.VK_C, Shortcut.GROUP_LAYER), 100);
+                Shortcut.registerShortcut("subwindow:conflict", tr("Toggle: {0}", tr("Conflict")), KeyEvent.VK_C, Shortcut.GROUP_LAYER), 100);
         displaylist.setCellRenderer(new OsmPrimitivRenderer());
         displaylist.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION);
         displaylist.addMouseListener(new MouseAdapter(){
             @Override public void mouseClicked(MouseEvent e) {
-                if (e.getClickCount() >= 2)
+                if (e.getClickCount() >= 2) {
                     resolve();
+                }
             }
         });
@@ -102,5 +104,5 @@
             }
         });
-        
+
         rebuildList();
     }
@@ -110,5 +112,5 @@
         method = method.trim().toLowerCase();
         if (method.equals("traditional")) {
-            resolveTraditional();            
+            resolveTraditional();
         } else if (method.equals("extended")) {
             resolveExtended();
@@ -118,31 +120,32 @@
         }
     }
-    
-    
+
+
     private final void resolveExtended() {
-        if(model.size() == 1)
+        if(model.size() == 1) {
             displaylist.setSelectedIndex(0);
-        
+        }
+
         if (displaylist.getSelectedIndex() == -1)
             return;
-        
+
         int [] selectedRows = displaylist.getSelectedIndices();
-        if (selectedRows == null || selectedRows.length == 0) {
-            return; 
-        }
+        if (selectedRows == null || selectedRows.length == 0)
+            return;
         int row = selectedRows[0];
         OsmPrimitive my = (OsmPrimitive)model.get(row);
         OsmPrimitive their = conflicts.get(my);
-        ConflictResolutionDialog dialog = new ConflictResolutionDialog(Main.parent);      
+        ConflictResolutionDialog dialog = new ConflictResolutionDialog(Main.parent);
         dialog.getConflictResolver().populate(my, their);
         dialog.setVisible(true);
         Main.map.mapView.repaint();
     }
-    
-    
+
+
     private final void resolveTraditional() {
-        if(model.size() == 1)
+        if(model.size() == 1) {
             displaylist.setSelectedIndex(0);
-        
+        }
+
         if (displaylist.getSelectedIndex() == -1)
             return;
@@ -154,9 +157,9 @@
         ConflictResolver resolver = new ConflictResolver(sel);
         int answer = new ExtendedDialog(Main.parent,
-                          tr("Resolve Conflicts"),
-                          resolver,
-                          new String[] { tr("Solve Conflict"), tr("Cancel") },
-                          new String[] { "dialogs/conflict.png", "cancel.png"} 
-        ).getValue(); 
+                tr("Resolve Conflicts"),
+                resolver,
+                new String[] { tr("Solve Conflict"), tr("Cancel") },
+                new String[] { "dialogs/conflict.png", "cancel.png"}
+        ).getValue();
 
         if (answer != 1)
@@ -171,5 +174,5 @@
             model.addElement(osm);
         }
-        
+
         if(model.size() != 0) {
             setTitle(tr("Conflicts: {0}", model.size()), true);
@@ -177,5 +180,5 @@
             setTitle(tr("Conflicts"), false);
         }
-        
+
         sbSelect.setEnabled(model.size() > 0);
         sbResolve.setEnabled(model.size() > 0);
@@ -185,4 +188,33 @@
         this.conflicts.putAll(conflicts);
         rebuildList();
+    }
+
+
+    /**
+     * removes a conflict registered for {@see OsmPrimitive} <code>my</code>
+     * 
+     * @param my the {@see OsmPrimitive} for which a conflict is registered
+     *   with this dialog
+     */
+    public void removeConflictForPrimitive(OsmPrimitive my) {
+        if (! conflicts.keySet().contains(my))
+            return;
+        conflicts.remove(my);
+        rebuildList();
+        repaint();
+    }
+
+    /**
+     * registers a conflict with this dialog. The conflict is represented
+     * by a pair of {@see OsmPrimitive} with differences in their tag sets,
+     * their node lists (for {@see Way}s) or their member lists (for {@see Relation}s)
+     * 
+     * @param my  my version of the {@see OsmPrimitive}
+     * @param their their version of the {@see OsmPrimitive}
+     */
+    public void addConflict(OsmPrimitive my, OsmPrimitive their) {
+        conflicts.put(my, their);
+        rebuildList();
+        repaint();
     }
 
@@ -222,6 +254,7 @@
             }
             public void visit(Relation e) {
-                for (RelationMember em : e.members)
+                for (RelationMember em : e.members) {
                     em.member.visit(this);
+                }
             }
         };
Index: /trunk/src/org/openstreetmap/josm/gui/dialogs/ConflictResolutionDialog.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/dialogs/ConflictResolutionDialog.java	(revision 1641)
+++ /trunk/src/org/openstreetmap/josm/gui/dialogs/ConflictResolutionDialog.java	(revision 1642)
@@ -169,4 +169,25 @@
 
         public void actionPerformed(ActionEvent arg0) {
+            if (! resolver.isCompletelyResolved()) {
+                Object[] options = {
+                        tr("Apply partial resolutions"),
+                        tr("Continue resolving")};
+                int n = JOptionPane.showOptionDialog(null,
+                        tr("<html>You didn''t finish to resolve all conflicts.<br>"
+                                + "Click <strong>{0}</strong> to apply already resolved conflicts anyway.<br>"
+                                + "You can resolve the remaining conflicts later.<br>"
+                                + "Click <strong>{1}</strong> to return to resolving conflicts.</html>"
+                                , options[0].toString(), options[1].toString()
+                        ),
+                        tr("Warning"),
+                        JOptionPane.YES_NO_OPTION,
+                        JOptionPane.WARNING_MESSAGE,
+                        null,
+                        options,
+                        options[1]
+                );
+                if (n == JOptionPane.NO_OPTION || n == JOptionPane.CLOSED_OPTION)
+                    return;
+            }
             Command cmd = resolver.buildResolveCommand();
             Main.main.undoRedo.add(cmd);
