Index: trunk/src/org/openstreetmap/josm/actions/CombineWayAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/CombineWayAction.java	(revision 2219)
+++ trunk/src/org/openstreetmap/josm/actions/CombineWayAction.java	(revision 2220)
@@ -2,4 +2,7 @@
 package org.openstreetmap.josm.actions;
 
+import static org.openstreetmap.josm.gui.conflict.tags.TagConflictResolutionUtil.combineTigerTags;
+import static org.openstreetmap.josm.gui.conflict.tags.TagConflictResolutionUtil.completeTagCollectionForEditing;
+import static org.openstreetmap.josm.gui.conflict.tags.TagConflictResolutionUtil.normalizeTagCollectionBeforeEditing;
 import static org.openstreetmap.josm.tools.I18n.tr;
 
@@ -30,7 +33,5 @@
 import org.openstreetmap.josm.data.osm.Relation;
 import org.openstreetmap.josm.data.osm.RelationMember;
-import org.openstreetmap.josm.data.osm.Tag;
 import org.openstreetmap.josm.data.osm.TagCollection;
-import org.openstreetmap.josm.data.osm.TigerUtils;
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.gui.ExtendedDialog;
@@ -38,5 +39,4 @@
 import org.openstreetmap.josm.tools.Pair;
 import org.openstreetmap.josm.tools.Shortcut;
-
 /**
  * Combines multiple ways into one.
@@ -88,41 +88,4 @@
     }
 
-    protected static void completeTagCollectionWithMissingTags(TagCollection tc, Collection<? extends OsmPrimitive> merged) {
-        for (String key: tc.getKeys()) {
-            // make sure the empty value is in the tag set if a tag is not present
-            // on all merged nodes
-            //
-            for (OsmPrimitive p: merged) {
-                if (p.get(key) == null) {
-                    tc.add(new Tag(key)); // add a tag with key and empty value
-                }
-            }
-        }
-        // remove irrelevant tags
-        //
-        tc.removeByKey("created_by");
-    }
-
-    /**
-     * Combines tags from TIGER data
-     * 
-     * @param tc the tag collection
-     */
-    protected static void combineTigerTags(TagCollection tc) {
-        for (String key: tc.getKeys()) {
-            if (TigerUtils.isTigerTag(key)) {
-                tc.setUniqueForKey(key, TigerUtils.combineTags(key, tc.getValues(key)));
-            }
-        }
-    }
-
-    protected static void completeTagCollectionForEditing(TagCollection tc) {
-        for (String key: tc.getKeys()) {
-            // make sure the empty value is in the tag set such that we can delete the tag
-            // in the conflict dialog if necessary
-            //
-            tc.add(new Tag(key,""));
-        }
-    }
 
     public void combineWays(Collection<Way> ways) {
@@ -170,10 +133,10 @@
         TagCollection completeWayTags = new TagCollection(wayTags);
         combineTigerTags(completeWayTags);
-        completeTagCollectionWithMissingTags(completeWayTags, ways);
+        normalizeTagCollectionBeforeEditing(completeWayTags, ways);
         TagCollection tagsToEdit = new TagCollection(completeWayTags);
         completeTagCollectionForEditing(tagsToEdit);
 
         CombinePrimitiveResolverDialog dialog = CombinePrimitiveResolverDialog.getInstance();
-        dialog.getTagConflictResolverModel().populate(tagsToEdit);
+        dialog.getTagConflictResolverModel().populate(tagsToEdit, completeWayTags.getKeysWithMultipleValues());
         dialog.setTargetPrimitive(targetWay);
         dialog.getRelationMemberConflictResolverModel().populate(
Index: trunk/src/org/openstreetmap/josm/actions/MergeNodesAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/MergeNodesAction.java	(revision 2219)
+++ trunk/src/org/openstreetmap/josm/actions/MergeNodesAction.java	(revision 2220)
@@ -2,4 +2,7 @@
 package org.openstreetmap.josm.actions;
 
+import static org.openstreetmap.josm.gui.conflict.tags.TagConflictResolutionUtil.combineTigerTags;
+import static org.openstreetmap.josm.gui.conflict.tags.TagConflictResolutionUtil.completeTagCollectionForEditing;
+import static org.openstreetmap.josm.gui.conflict.tags.TagConflictResolutionUtil.normalizeTagCollectionBeforeEditing;
 import static org.openstreetmap.josm.tools.I18n.tr;
 
@@ -23,7 +26,5 @@
 import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.data.osm.Tag;
 import org.openstreetmap.josm.data.osm.TagCollection;
-import org.openstreetmap.josm.data.osm.TigerUtils;
 import org.openstreetmap.josm.data.osm.Way;
 import org.openstreetmap.josm.data.osm.BackreferencedDataSet.RelationToChildReference;
@@ -59,5 +60,4 @@
         }
 
-
         Node targetNode = selectTargetNode(selectedNodes);
         Command cmd = mergeNodes(Main.main.getEditLayer(), selectedNodes, targetNode);
@@ -65,42 +65,4 @@
             Main.main.undoRedo.add(cmd);
             Main.main.getEditLayer().data.setSelected(targetNode);
-        }
-    }
-
-    protected static void completeTagCollectionWithMissingTags(TagCollection tc, Collection<Node> mergedNodes) {
-        for (String key: tc.getKeys()) {
-            // make sure the empty value is in the tag set if a tag is not present
-            // on all merged nodes
-            //
-            for (Node n: mergedNodes) {
-                if (n.get(key) == null) {
-                    tc.add(new Tag(key)); // add a tag with key and empty value
-                }
-            }
-        }
-        // remove irrelevant tags
-        //
-        tc.removeByKey("created_by");
-    }
-
-    protected static void completeTagCollectionForEditing(TagCollection tc) {
-        for (String key: tc.getKeys()) {
-            // make sure the empty value is in the tag set such that we can delete the tag
-            // in the conflict dialog if necessary
-            //
-            tc.add(new Tag(key,""));
-        }
-    }
-
-    /**
-     * Combines tags from TIGER data
-     * 
-     * @param tc the tag collection
-     */
-    protected static void combineTigerTags(TagCollection tc) {
-        for (String key: tc.getKeys()) {
-            if (TigerUtils.isTigerTag(key)) {
-                tc.setUniqueForKey(key, TigerUtils.combineTags(key, tc.getValues(key)));
-            }
         }
     }
@@ -220,5 +182,5 @@
 
     /**
-     * Merges the nodes in <code>node</code> onto one of the nodes. Uses the dataset
+     * Merges the nodes in <code>nodes</code> onto one of the nodes. Uses the dataset
      * managed by <code>layer</code> as reference. <code>backreferences</code> is a precomputed
      * collection of all parent/child references in the dataset.
@@ -250,5 +212,5 @@
         TagCollection nodeTags = TagCollection.unionOfAllPrimitives(nodes);
         combineTigerTags(nodeTags);
-        completeTagCollectionWithMissingTags(nodeTags, nodes);
+        normalizeTagCollectionBeforeEditing(nodeTags, nodes);
         TagCollection nodeTagsToEdit = new TagCollection(nodeTags);
         completeTagCollectionForEditing(nodeTagsToEdit);
@@ -257,8 +219,11 @@
         //
         CombinePrimitiveResolverDialog dialog = CombinePrimitiveResolverDialog.getInstance();
-        dialog.getTagConflictResolverModel().populate(nodeTagsToEdit);
+        dialog.getTagConflictResolverModel().populate(nodeTagsToEdit, nodeTags.getKeysWithMultipleValues());
         dialog.getRelationMemberConflictResolverModel().populate(relationToNodeReferences);
         dialog.setTargetPrimitive(targetNode);
         dialog.prepareDefaultDecisions();
+        // conflict resolution is necessary if there are conflicts in the merged tags
+        // or if at least one of the merged nodes is referred to by a relation
+        //
         if (! nodeTags.isApplicableToPrimitive() || relationToNodeReferences.size() > 1) {
             dialog.setVisible(true);
@@ -283,7 +248,5 @@
         if (wayFixCommands == null)
             return null;
-        else {
-            cmds.addAll(wayFixCommands);
-        }
+        cmds.addAll(wayFixCommands);
 
         // build the commands
@@ -299,5 +262,4 @@
         return cmd;
     }
-
 
     /**
Index: trunk/src/org/openstreetmap/josm/actions/PasteTagsAction.java
===================================================================
--- trunk/src/org/openstreetmap/josm/actions/PasteTagsAction.java	(revision 2219)
+++ trunk/src/org/openstreetmap/josm/actions/PasteTagsAction.java	(revision 2220)
@@ -38,5 +38,5 @@
 
     static private List<Class<? extends OsmPrimitive>> osmPrimitiveClasses;
-    {
+    static {
         osmPrimitiveClasses = new ArrayList<Class<? extends OsmPrimitive>>();
         osmPrimitiveClasses.add(Node.class);
@@ -60,22 +60,4 @@
 
     /**
-     * Replies the subset  of {@see OsmPrimitive}s of <code>type</code> from <code>superSet</code>.
-     * 
-     * @param <T>
-     * @param superSet  the super set of primitives
-     * @param type  the type
-     * @return
-     */
-    protected <T extends OsmPrimitive> Collection<? extends OsmPrimitive> getSubcollectionByType(Collection<? extends OsmPrimitive> superSet, Class<T> type) {
-        Collection<OsmPrimitive> ret = new ArrayList<OsmPrimitive>();
-        for (OsmPrimitive p : superSet) {
-            if (type.isInstance(p)) {
-                ret.add(p);
-            }
-        }
-        return ret;
-    }
-
-    /**
      * Replies all primitives of type <code>type</code> in the current selection.
      * 
@@ -85,5 +67,5 @@
      */
     protected <T extends OsmPrimitive> Collection<? extends OsmPrimitive> getSourcePrimitivesByType(Class<T> type) {
-        return getSubcollectionByType(Main.pasteBuffer.getSelected(), type);
+        return OsmPrimitive.getFilteredList(Main.pasteBuffer.getSelected(), type);
     }
 
@@ -145,5 +127,5 @@
         HashMap<OsmPrimitiveType, Integer> ret = new HashMap<OsmPrimitiveType, Integer>();
         for (Class<? extends OsmPrimitive> type: osmPrimitiveClasses) {
-            int count = getSubcollectionByType(getEditLayer().data.getSelected(), type).size();
+            int count = OsmPrimitive.getFilteredList(getEditLayer().data.getSelected(), type).size();
             if (count > 0) {
                 ret.put(OsmPrimitiveType.from(type), count);
@@ -173,5 +155,4 @@
             // no tags found to paste. Abort.
             return;
-
 
         if (!tc.isApplicableToPrimitive()) {
@@ -202,6 +183,6 @@
      * <code>selection</code>
      */
-    protected <T extends OsmPrimitive> boolean hasTargetPrimitives(Collection<? extends OsmPrimitive> selection, Class<T> type) {
-        return !getSubcollectionByType(selection, type).isEmpty();
+    protected <T extends OsmPrimitive> boolean hasTargetPrimitives(Collection<OsmPrimitive> selection, Class<T> type) {
+        return !OsmPrimitive.getFilteredList(selection, type).isEmpty();
     }
 
@@ -212,5 +193,5 @@
      * @return true if this a heterogeneous source can be pasted without conflicts to targets
      */
-    protected boolean canPasteFromHeterogeneousSourceWithoutConflict(Collection<? extends OsmPrimitive> targets) {
+    protected boolean canPasteFromHeterogeneousSourceWithoutConflict(Collection<OsmPrimitive> targets) {
         if (hasTargetPrimitives(targets, Node.class)) {
             TagCollection tc = TagCollection.unionOfAllPrimitives(getSourcePrimitivesByType(Node.class));
@@ -237,5 +218,5 @@
      * @param targets the collection of target primitives
      */
-    protected void pasteFromHeterogeneousSource(Collection<? extends OsmPrimitive> targets) {
+    protected void pasteFromHeterogeneousSource(Collection<OsmPrimitive> targets) {
         if (canPasteFromHeterogeneousSourceWithoutConflict(targets)) {
             if (hasSourceTagsByType(Node.class) && hasTargetPrimitives(targets, Node.class)) {
@@ -264,13 +245,13 @@
                 return;
             if (hasSourceTagsByType(Node.class) && hasTargetPrimitives(targets, Node.class)) {
-                Command cmd = buildChangeCommand(getSubcollectionByType(targets, Node.class), dialog.getResolution(OsmPrimitiveType.NODE));
+                Command cmd = buildChangeCommand(OsmPrimitive.getFilteredList(targets, Node.class), dialog.getResolution(OsmPrimitiveType.NODE));
                 Main.main.undoRedo.add(cmd);
             }
             if (hasSourceTagsByType(Way.class) && hasTargetPrimitives(targets, Way.class)) {
-                Command cmd = buildChangeCommand(getSubcollectionByType(targets, Way.class), dialog.getResolution(OsmPrimitiveType.WAY));
+                Command cmd = buildChangeCommand(OsmPrimitive.getFilteredList(targets, Way.class), dialog.getResolution(OsmPrimitiveType.WAY));
                 Main.main.undoRedo.add(cmd);
             }
             if (hasSourceTagsByType(Relation.class) && hasTargetPrimitives(targets, Relation.class)) {
-                Command cmd = buildChangeCommand(getSubcollectionByType(targets, Relation.class), dialog.getResolution(OsmPrimitiveType.RELATION));
+                Command cmd = buildChangeCommand(OsmPrimitive.getFilteredList(targets, Relation.class), dialog.getResolution(OsmPrimitiveType.RELATION));
                 Main.main.undoRedo.add(cmd);
             }
Index: trunk/src/org/openstreetmap/josm/gui/conflict/tags/CombinePrimitiveResolverDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/conflict/tags/CombinePrimitiveResolverDialog.java	(revision 2219)
+++ trunk/src/org/openstreetmap/josm/gui/conflict/tags/CombinePrimitiveResolverDialog.java	(revision 2220)
@@ -8,4 +8,6 @@
 import java.awt.FlowLayout;
 import java.awt.event.ActionEvent;
+import java.awt.event.HierarchyBoundsListener;
+import java.awt.event.HierarchyEvent;
 import java.awt.event.WindowAdapter;
 import java.awt.event.WindowEvent;
@@ -36,6 +38,6 @@
 
 /**
- * This dialog helps to resolve conflicts occurring when ways are combined ore
- * primitives are merged.
+ * This dialog helps to resolve conflicts occurring when ways are combined or
+ * nodes are merged.
  * 
  * There is a singleton instance of this dialog which can be retrieved using
@@ -57,5 +59,5 @@
  * merged to, see {@see #setTargetPrimitive(OsmPrimitive)}.
  * 
- * After the dialog closed use {@see #isCancelled()} to check whether the user cancelled
+ * After the dialog is closed use {@see #isCancelled()} to check whether the user canceled
  * the dialog. If it wasn't canceled you may build a collection of {@see Command} objects
  * which reflect the conflict resolution decisions the user made in the dialog:
@@ -66,6 +68,12 @@
 public class CombinePrimitiveResolverDialog extends JDialog {
 
+    /** the unique instance of the dialog */
     static private CombinePrimitiveResolverDialog instance;
 
+    /**
+     * Replies the unique instance of the dialog
+     * 
+     * @return the unique instance of the dialog
+     */
     public static CombinePrimitiveResolverDialog getInstance() {
         if (instance == null) {
@@ -75,5 +83,5 @@
     }
 
-    private JSplitPane spTagConflictTypes;
+    private AutoAdjustingSplitPane spTagConflictTypes;
     private TagConflictResolver pnlTagConflictResolver;
     private RelationMemberConflictResolver pnlRelationMemberConflictResolver;
@@ -82,10 +90,20 @@
     private OsmPrimitive targetPrimitive;
 
-
-
+    /**
+     * Replies the target primitive the collection of primitives is merged
+     * or combined to.
+     * 
+     * @return the target primitive
+     */
     public OsmPrimitive getTargetPrimitmive() {
         return targetPrimitive;
     }
 
+    /**
+     * Sets the primitive the collection of primitives is merged or combined
+     * to.
+     * 
+     * @param primitive the target primitive
+     */
     public void setTargetPrimitive(OsmPrimitive primitive) {
         this.targetPrimitive = primitive;
@@ -118,5 +136,5 @@
         getContentPane().setLayout(new BorderLayout());
         updateTitle();
-        spTagConflictTypes = new JSplitPane(JSplitPane.VERTICAL_SPLIT);
+        spTagConflictTypes = new AutoAdjustingSplitPane(JSplitPane.VERTICAL_SPLIT);
         spTagConflictTypes.setTopComponent(buildTagConflictResolverPanel());
         spTagConflictTypes.setBottomComponent(buildRelationMemberConflictResolverPanel());
@@ -218,5 +236,5 @@
             }
         }
-        model.refresh();
+        model.rebuild();
     }
 
@@ -245,15 +263,23 @@
         TagConflictResolverModel tagModel = getTagConflictResolverModel();
         getContentPane().removeAll();
+
         if (relModel.getNumDecisions() > 0 && tagModel.getNumDecisions() > 0) {
+            // display both, the dialog for resolving relation conflicts and for resolving
+            // tag conflicts
             spTagConflictTypes.setTopComponent(pnlTagConflictResolver);
             spTagConflictTypes.setBottomComponent(pnlRelationMemberConflictResolver);
             getContentPane().add(spTagConflictTypes, BorderLayout.CENTER);
         } else if (relModel.getNumDecisions() > 0) {
+            // relation conflicts only
+            //
             getContentPane().add(pnlRelationMemberConflictResolver, BorderLayout.CENTER);
         } else if (tagModel.getNumDecisions() >0) {
+            // tag conflicts only
+            //
             getContentPane().add(pnlTagConflictResolver, BorderLayout.CENTER);
         } else {
             getContentPane().add(buildEmptyConflictsPanel(), BorderLayout.CENTER);
         }
+
         getContentPane().add(pnlButtons, BorderLayout.SOUTH);
         validate();
@@ -348,3 +374,30 @@
         }
     }
+
+    class AutoAdjustingSplitPane extends JSplitPane implements PropertyChangeListener, HierarchyBoundsListener {
+        private double dividerLocation;
+
+        public AutoAdjustingSplitPane(int newOrientation) {
+            super(newOrientation);
+            addPropertyChangeListener(JSplitPane.DIVIDER_LOCATION_PROPERTY,this);
+            addHierarchyBoundsListener(this);
+        }
+
+        public void ancestorResized(HierarchyEvent e) {
+            setDividerLocation((int)(dividerLocation * getHeight()));
+        }
+
+        public void ancestorMoved(HierarchyEvent e) {
+            // do nothing
+        }
+
+        public void propertyChange(PropertyChangeEvent evt) {
+            if (evt.getPropertyName().equals(JSplitPane.DIVIDER_LOCATION_PROPERTY)) {
+                int newVal = (Integer)evt.getNewValue();
+                if (getHeight() != 0) {
+                    dividerLocation = (double)newVal / (double)getHeight();
+                }
+            }
+        }
+    }
 }
Index: trunk/src/org/openstreetmap/josm/gui/conflict/tags/MultiValueCellRenderer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/conflict/tags/MultiValueCellRenderer.java	(revision 2219)
+++ trunk/src/org/openstreetmap/josm/gui/conflict/tags/MultiValueCellRenderer.java	(revision 2220)
@@ -4,4 +4,5 @@
 import static org.openstreetmap.josm.tools.I18n.tr;
 
+import java.awt.Color;
 import java.awt.Component;
 import java.awt.Font;
@@ -20,7 +21,8 @@
  * This is a {@see TableCellRenderer} for {@see MultiValueResolutionDecision}s.
  * 
-
  */
 public class MultiValueCellRenderer extends JLabel implements TableCellRenderer {
+
+    public final static Color BGCOLOR_UNDECIDED = new Color(255,197,197);
 
     private ImageIcon iconDecided;
@@ -36,11 +38,23 @@
     }
 
-    protected void renderColors(boolean selected) {
+    protected void renderColors(MultiValueResolutionDecision decision, boolean selected) {
         if (selected) {
             setForeground(UIManager.getColor("Table.selectionForeground"));
             setBackground(UIManager.getColor("Table.selectionBackground"));
-        } else {
-            setForeground(UIManager.getColor("Table.foreground"));
-            setBackground(UIManager.getColor("Table.background"));
+        } else{
+            switch(decision.getDecisionType()) {
+                case UNDECIDED:
+                    setForeground(UIManager.getColor("Table.foreground"));
+                    setBackground(BGCOLOR_UNDECIDED);
+                    break;
+                case KEEP_NONE:
+                    setForeground(UIManager.getColor("Panel.foreground"));
+                    setBackground(UIManager.getColor("Panel.background"));
+                    break;
+                default:
+                    setForeground(UIManager.getColor("Table.foreground"));
+                    setBackground(UIManager.getColor("Table.background"));
+                    break;
+            }
         }
     }
@@ -49,26 +63,26 @@
         model.removeAllElements();
         switch(decision.getDecisionType()) {
-        case UNDECIDED:
-            model.addElement(tr("Choose a value"));
-            setFont(getFont().deriveFont(Font.ITALIC));
-            setToolTipText(tr("Please decided which values to keep"));
-            cbDecisionRenderer.setSelectedIndex(0);
-            break;
-        case KEEP_ONE:
-            model.addElement(decision.getChosenValue());
-            setToolTipText(tr("Value ''{0}'' is going to be applied for key ''{1}''", decision.getChosenValue(), decision.getKey()));
-            cbDecisionRenderer.setSelectedIndex(0);
-            break;
-        case KEEP_NONE:
-            model.addElement(tr("deleted"));
-            setFont(getFont().deriveFont(Font.ITALIC));
-            setToolTipText(tr("The key ''{0}'' and all its values are going to be removed", decision.getKey()));
-            cbDecisionRenderer.setSelectedIndex(0);
-            break;
-        case KEEP_ALL:
-            model.addElement(decision.getChosenValue());
-            setToolTipText(tr("All values joined as ''{0}'' are going to be applied for key ''{1}''", decision.getChosenValue(), decision.getKey()));
-            cbDecisionRenderer.setSelectedIndex(0);
-            break;
+            case UNDECIDED:
+                model.addElement(tr("Choose a value"));
+                setFont(getFont().deriveFont(Font.ITALIC));
+                setToolTipText(tr("Please decide which values to keep"));
+                cbDecisionRenderer.setSelectedIndex(0);
+                break;
+            case KEEP_ONE:
+                model.addElement(decision.getChosenValue());
+                setToolTipText(tr("Value ''{0}'' is going to be applied for key ''{1}''", decision.getChosenValue(), decision.getKey()));
+                cbDecisionRenderer.setSelectedIndex(0);
+                break;
+            case KEEP_NONE:
+                model.addElement(tr("deleted"));
+                setFont(getFont().deriveFont(Font.ITALIC));
+                setToolTipText(tr("The key ''{0}'' and all its values are going to be removed", decision.getKey()));
+                cbDecisionRenderer.setSelectedIndex(0);
+                break;
+            case KEEP_ALL:
+                model.addElement(decision.getChosenValue());
+                setToolTipText(tr("All values joined as ''{0}'' are going to be applied for key ''{1}''", decision.getChosenValue(), decision.getKey()));
+                cbDecisionRenderer.setSelectedIndex(0);
+                break;
         }
     }
@@ -84,22 +98,22 @@
 
         reset();
-        renderColors(isSelected);
         MultiValueResolutionDecision decision = (MultiValueResolutionDecision)value;
+        renderColors(decision,isSelected);
         switch(column) {
-        case 0:
-            if (decision.isDecided()) {
-                setIcon(iconDecided);
-            } else {
-                setIcon(iconUndecided);
-            }
-            return this;
+            case 0:
+                if (decision.isDecided()) {
+                    setIcon(iconDecided);
+                } else {
+                    setIcon(iconUndecided);
+                }
+                return this;
 
-        case 1:
-            setText(decision.getKey());
-            return this;
+            case 1:
+                setText(decision.getKey());
+                return this;
 
-        case 2:
-            renderValue(decision);
-            return cbDecisionRenderer;
+            case 2:
+                renderValue(decision);
+                return cbDecisionRenderer;
         }
         return this;
Index: trunk/src/org/openstreetmap/josm/gui/conflict/tags/PasteTagsConflictResolverDialog.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/conflict/tags/PasteTagsConflictResolverDialog.java	(revision 2219)
+++ trunk/src/org/openstreetmap/josm/gui/conflict/tags/PasteTagsConflictResolverDialog.java	(revision 2220)
@@ -107,5 +107,4 @@
     }
 
-
     protected JPanel buildButtonPanel() {
         JPanel pnl = new JPanel();
@@ -135,6 +134,14 @@
     }
 
+    /**
+     * Initializes the conflict resolver for a specific type of primitives
+     * 
+     * @param type the type of primitives
+     * @param tc the tags belonging to this type of primitives
+     * @param targetStatistics histogram of paste targets, number of primitives of each type in the paste target
+     */
     protected void initResolver(OsmPrimitiveType type, TagCollection tc, Map<OsmPrimitiveType,Integer> targetStatistics) {
-        resolvers.get(type).getModel().populate(tc);
+        resolvers.get(type).getModel().populate(tc,tc.getKeysWithMultipleValues());
+        resolvers.get(type).getModel().prepareDefaultTagDecisions();
         if (!tc.isEmpty() && targetStatistics.get(type) != null && targetStatistics.get(type) > 0) {
             tpResolvers.add(PANE_TITLES.get(type), resolvers.get(type));
@@ -142,14 +149,11 @@
     }
 
-    protected String formatStatisticsMessage(OsmPrimitiveType type, int count) {
-        String msg = "";
-        switch(type) {
-            case NODE: msg= trn("{0} node", "{0} nodes", count, count); break;
-            case WAY: msg= trn("{0} way", "{0} ways", count, count); break;
-            case RELATION: msg= trn("{0} relation", "{0} relations", count, count); break;
-        }
-        return msg;
-    }
-
+    /**
+     * Populates the conflict resolver with one tag collection
+     * 
+     * @param tagsForAllPrimitives  the tag collection
+     * @param sourceStatistics histogram of tag source, number of primitives of each type in the source
+     * @param targetStatistics histogram of paste targets, number of primitives of each type in the paste target
+     */
     public void populate(TagCollection tagsForAllPrimitives, Map<OsmPrimitiveType, Integer> sourceStatistics, Map<OsmPrimitiveType,Integer> targetStatistics) {
         mode = Mode.RESOLVING_ONE_TAGCOLLECTION_ONLY;
@@ -157,5 +161,11 @@
         sourceStatistics = sourceStatistics == null ? new HashMap<OsmPrimitiveType, Integer>() :sourceStatistics;
         targetStatistics = targetStatistics == null ? new HashMap<OsmPrimitiveType, Integer>() : targetStatistics;
-        allPrimitivesResolver.getModel().populate(tagsForAllPrimitives);
+
+        // init the resolver
+        //
+        allPrimitivesResolver.getModel().populate(tagsForAllPrimitives,tagsForAllPrimitives.getKeysWithMultipleValues());
+        allPrimitivesResolver.getModel().prepareDefaultTagDecisions();
+
+        // prepare the dialog with one tag resolver
         pnlTagResolver.setLayout(new BorderLayout());
         pnlTagResolver.removeAll();
@@ -183,4 +193,13 @@
     }
 
+    /**
+     * Populate the tag conflict resolver with tags for each type of primitives
+     * 
+     * @param tagsForNodes the tags belonging to nodes in the paste source
+     * @param tagsForWays the tags belonging to way in the paste source
+     * @param tagsForRelations the tags belonging to relations in the paste source
+     * @param sourceStatistics histogram of tag source, number of primitives of each type in the source
+     * @param targetStatistics histogram of paste targets, number of primitives of each type in the paste target
+     */
     public void populate(TagCollection tagsForNodes, TagCollection tagsForWays, TagCollection tagsForRelations, Map<OsmPrimitiveType,Integer> sourceStatistics, Map<OsmPrimitiveType, Integer> targetStatistics) {
         tagsForNodes = (tagsForNodes == null) ? new TagCollection() : tagsForNodes;
@@ -426,16 +445,15 @@
         }
 
-        protected void renderFrom(StatisticsInfo info) {
-            if (info == null) return;
-            if (info.sourceInfo == null) return;
-            if (info.sourceInfo.isEmpty()) return;
-            if (info.sourceInfo.size() == 1) {
-                setIcon(ImageProvider.get(info.sourceInfo.keySet().iterator().next()));
+        protected void renderStatistics(Map<OsmPrimitiveType, Integer> stat) {
+            if (stat == null) return;
+            if (stat.isEmpty()) return;
+            if (stat.size() == 1) {
+                setIcon(ImageProvider.get(stat.keySet().iterator().next()));
             } else {
                 setIcon(ImageProvider.get("data", "object"));
             }
             String text = "";
-            for (OsmPrimitiveType type: info.sourceInfo.keySet()) {
-                int numPrimitives = info.sourceInfo.get(type) == null ? 0 : info.sourceInfo.get(type);
+            for (OsmPrimitiveType type: stat.keySet()) {
+                int numPrimitives = stat.get(type) == null ? 0 : stat.get(type);
                 if (numPrimitives == 0) {
                     continue;
@@ -452,28 +470,10 @@
         }
 
+        protected void renderFrom(StatisticsInfo info) {
+            renderStatistics(info.sourceInfo);
+        }
+
         protected void renderTo(StatisticsInfo info) {
-            if (info == null) return;
-            if (info.targetInfo == null) return;
-            if (info.targetInfo.isEmpty()) return;
-            if (info.targetInfo.size() == 1) {
-                setIcon(ImageProvider.get(info.targetInfo.keySet().iterator().next()));
-            } else {
-                setIcon(ImageProvider.get("data", "object"));
-            }
-            String text = "";
-            for (OsmPrimitiveType type: info.targetInfo.keySet()) {
-                int numPrimitives = info.targetInfo.get(type) == null ? 0 : info.targetInfo.get(type);
-                if (numPrimitives == 0) {
-                    continue;
-                }
-                String msg = "";
-                switch(type) {
-                    case NODE: msg = trn("{0} node", "{0} nodes", numPrimitives,numPrimitives); break;
-                    case WAY: msg = trn("{0} way", "{0} ways", numPrimitives, numPrimitives); break;
-                    case RELATION: msg = trn("{0} relation", "{0} relations", numPrimitives, numPrimitives); break;
-                }
-                text = text.equals("") ? msg : text + ", " + msg;
-            }
-            setText(text);
+            renderStatistics(info.targetInfo);
         }
 
Index: trunk/src/org/openstreetmap/josm/gui/conflict/tags/TagConflictResolutionUtil.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/conflict/tags/TagConflictResolutionUtil.java	(revision 2220)
+++ trunk/src/org/openstreetmap/josm/gui/conflict/tags/TagConflictResolutionUtil.java	(revision 2220)
@@ -0,0 +1,88 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.conflict.tags;
+
+import java.util.Collection;
+
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.Tag;
+import org.openstreetmap.josm.data.osm.TagCollection;
+import org.openstreetmap.josm.data.osm.TigerUtils;
+
+/**
+ * Collection of utility methods for tag conflict resolution
+ * 
+ */
+public class TagConflictResolutionUtil {
+
+    /** no constructor, just static utility methods */
+    private TagConflictResolutionUtil() {}
+
+
+    /**
+     * Normalizes the tags in the tag collection <code>tc</code> before resolving tag conflicts.
+     * 
+     *  Removes irrelevant tags like "created_by".
+     * 
+     *  For tags which are not present on at least one of the merged nodes, the empty value ""
+     *  is added to the list of values for this tag, but only if there are at least two
+     *  primitives with tags.
+     * 
+     * @param tc the tag collection
+     * @param merged the collection of merged  primitives
+     */
+    public static void normalizeTagCollectionBeforeEditing(TagCollection tc, Collection<? extends OsmPrimitive> merged) {
+        // remove irrelevant tags
+        //
+        tc.removeByKey("created_by");
+
+        int numNodesWithTags = 0;
+        for (OsmPrimitive p: merged) {
+            if (p.getKeys().size() >0) {
+                numNodesWithTags++;
+            }
+        }
+        if (numNodesWithTags <= 1)
+            return;
+
+        for (String key: tc.getKeys()) {
+            // make sure the empty value is in the tag set if a tag is not present
+            // on all merged nodes
+            //
+            for (OsmPrimitive p: merged) {
+                if (p.get(key) == null) {
+                    tc.add(new Tag(key, "")); // add a tag with key and empty value
+                }
+            }
+        }
+    }
+
+    /**
+     * Combines tags from TIGER data
+     * 
+     * @param tc the tag collection
+     */
+    public static void combineTigerTags(TagCollection tc) {
+        for (String key: tc.getKeys()) {
+            if (TigerUtils.isTigerTag(key)) {
+                tc.setUniqueForKey(key, TigerUtils.combineTags(key, tc.getValues(key)));
+            }
+        }
+    }
+
+    /**
+     * Completes tags in the tag collection <code>tc</code> with the empty value
+     * for each tag. If the empty value is present the tag conflict resolution dialog
+     * will offer an option for removing the tag and not only options for selecting
+     * one of the current values of the tag.
+     * 
+     * @param tc the tag collection
+     */
+    public static void completeTagCollectionForEditing(TagCollection tc) {
+        for (String key: tc.getKeys()) {
+            // make sure the empty value is in the tag set such that we can delete the tag
+            // in the conflict dialog if necessary
+            //
+            tc.add(new Tag(key,""));
+        }
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/conflict/tags/TagConflictResolver.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/conflict/tags/TagConflictResolver.java	(revision 2219)
+++ trunk/src/org/openstreetmap/josm/gui/conflict/tags/TagConflictResolver.java	(revision 2220)
@@ -2,17 +2,75 @@
 package org.openstreetmap.josm.gui.conflict.tags;
 
+import static org.openstreetmap.josm.tools.I18n.tr;
+
 import java.awt.BorderLayout;
+import java.awt.GridBagConstraints;
+import java.awt.GridBagLayout;
 
+import javax.swing.BorderFactory;
+import javax.swing.JCheckBox;
+import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JScrollPane;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
 
+import org.openstreetmap.josm.Main;
+
+/**
+ * This is a UI widget for resolving tag conflicts, i.e. differences of the tag values
+ * of multiple {@see OsmPrimitive}s.
+ * 
+ *
+ */
 public class TagConflictResolver extends JPanel {
 
+    /** the model for the tag conflict resolver */
     private TagConflictResolverModel model;
+    /** selects wheter only tags with conflicts are displayed */
+    private JCheckBox cbShowTagsWithConflictsOnly;
+
+    protected JPanel buildInfoPanel() {
+        JPanel pnl = new JPanel();
+        pnl.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
+        pnl.setLayout(new GridBagLayout());
+        GridBagConstraints gc = new GridBagConstraints();
+        gc.fill = GridBagConstraints.BOTH;
+        gc.weighty = 1.0;
+        gc.weightx = 1.0;
+        gc.anchor = GridBagConstraints.LINE_START;
+        pnl.add(new JLabel(tr("<html>Please select the values to keep for the following tags.</html>")), gc);
+
+        gc.gridy = 1;
+        gc.fill = GridBagConstraints.HORIZONTAL;
+        gc.weighty = 0.0;
+        pnl.add(cbShowTagsWithConflictsOnly = new JCheckBox(tr("Show tags with conflicts only")), gc);
+        cbShowTagsWithConflictsOnly.addChangeListener(
+                new ChangeListener() {
+                    public void stateChanged(ChangeEvent e) {
+                        model.setShowTagsWithConflictsOnly(cbShowTagsWithConflictsOnly.isSelected());
+                    }
+                }
+        );
+        cbShowTagsWithConflictsOnly.setSelected(
+                Main.pref.getBoolean(getClass().getName() + ".showTagsWithConflictsOnly", false)
+        );
+        return pnl;
+    }
+
+    /**
+     * Remembers the current settings in the global preferences
+     * 
+     */
+    public void rememberPreferences() {
+        Main.pref.put(getClass().getName() + ".showTagsWithConflictsOnly", cbShowTagsWithConflictsOnly.isSelected());
+    }
 
     protected void build() {
         setLayout(new BorderLayout());
+        add(buildInfoPanel(), BorderLayout.NORTH);
         add(new JScrollPane(new TagConflictResolverTable(model)), BorderLayout.CENTER);
     }
+
     public TagConflictResolver() {
         this.model = new TagConflictResolverModel();
@@ -20,4 +78,9 @@
     }
 
+    /**
+     * Replies the model used by this dialog
+     * 
+     * @return the model
+     */
     public TagConflictResolverModel getModel() {
         return model;
Index: trunk/src/org/openstreetmap/josm/gui/conflict/tags/TagConflictResolverModel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/conflict/tags/TagConflictResolverModel.java	(revision 2219)
+++ trunk/src/org/openstreetmap/josm/gui/conflict/tags/TagConflictResolverModel.java	(revision 2220)
@@ -10,5 +10,7 @@
 import java.util.Comparator;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import javax.swing.table.DefaultTableModel;
@@ -20,8 +22,10 @@
 
     private TagCollection tags;
-    private List<String> keys;
+    private List<String> displayedKeys;
+    private Set<String> keysWithConflicts;
     private HashMap<String, MultiValueResolutionDecision> decisions;
     private int numConflicts;
     private PropertyChangeSupport support;
+    private boolean showTagsWithConflictsOnly = false;
 
     public TagConflictResolverModel() {
@@ -37,5 +41,4 @@
         support.removePropertyChangeListener(listener);
     }
-
 
     protected void setNumConflicts(int numConflicts) {
@@ -59,12 +62,12 @@
     protected void sort() {
         Collections.sort(
-                keys,
+                displayedKeys,
                 new Comparator<String>() {
-                    public int compare(String o1, String o2) {
-                        if (decisions.get(o1).isDecided() && ! decisions.get(o2).isDecided())
+                    public int compare(String key1, String key2) {
+                        if (decisions.get(key1).isDecided() && ! decisions.get(key2).isDecided())
                             return 1;
-                        else if (!decisions.get(o1).isDecided() && decisions.get(o2).isDecided())
+                        else if (!decisions.get(key1).isDecided() && decisions.get(key2).isDecided())
                             return -1;
-                        return o1.compareTo(o2);
+                        return key1.compareTo(key2);
                     }
                 }
@@ -72,35 +75,58 @@
     }
 
-    protected void init() {
-        keys.clear();
-        keys.addAll(tags.getKeys());
+    /**
+     * initializes the model from the current tags
+     * 
+     */
+    protected void rebuild() {
+        if (tags == null) return;
         for(String key: tags.getKeys()) {
             MultiValueResolutionDecision decision = new MultiValueResolutionDecision(tags.getTagsFor(key));
-            decisions.put(key,decision);
-        }
+            if (decisions.get(key) == null) {
+                decisions.put(key,decision);
+            }
+        }
+        displayedKeys.clear();
+        Set<String> keys = tags.getKeys();
+        if (showTagsWithConflictsOnly) {
+            keys.retainAll(keysWithConflicts);
+            for (String key: tags.getKeys()) {
+                if (!decisions.get(key).isDecided() && !keys.contains(key)) {
+                    keys.add(key);
+                }
+            }
+        }
+        displayedKeys.addAll(keys);
         refreshNumConflicts();
-    }
-
-    public void populate(TagCollection tags) {
+        sort();
+        fireTableDataChanged();
+    }
+
+    /**
+     * Populates the model with the tags for which conflicts are to be resolved.
+     * 
+     * @param tags  the tag collection with the tags. Must not be null.
+     * @param keysWithConflicts the set of tag keys with conflicts
+     * @throws IllegalArgumentException thrown if tags is null
+     */
+    public void populate(TagCollection tags, Set<String> keysWithConflicts) {
         if (tags == null)
             throw new IllegalArgumentException(tr("Parameter ''{0}'' must not be null.", "tags"));
         this.tags = tags;
-        keys = new ArrayList<String>();
+        displayedKeys = new ArrayList<String>();
+        this.keysWithConflicts = keysWithConflicts == null ? new HashSet<String>() : keysWithConflicts;
         decisions = new HashMap<String, MultiValueResolutionDecision>();
-        init();
-        sort();
-        fireTableDataChanged();
-    }
-
+        rebuild();
+    }
 
     @Override
     public int getRowCount() {
-        if (keys == null) return 0;
-        return keys.size();
+        if (displayedKeys == null) return 0;
+        return displayedKeys.size();
     }
 
     @Override
     public Object getValueAt(int row, int column) {
-        return decisions.get(keys.get(row));
+        return decisions.get(displayedKeys.get(row));
     }
 
@@ -112,5 +138,5 @@
     @Override
     public void setValueAt(Object value, int row, int column) {
-        MultiValueResolutionDecision decision = decisions.get(keys.get(row));
+        MultiValueResolutionDecision decision = decisions.get(displayedKeys.get(row));
         if (value instanceof String) {
             decision.keepOne((String)value);
@@ -150,5 +176,5 @@
     public TagCollection getResolution() {
         TagCollection tc = new TagCollection();
-        for (String key: keys) {
+        for (String key: displayedKeys) {
             tc.add(decisions.get(key).getResolution());
         }
@@ -157,10 +183,33 @@
 
     public MultiValueResolutionDecision getDecision(int row) {
-        return decisions.get(keys.get(row));
-    }
-
-    public void refresh() {
-        fireTableDataChanged();
-        refreshNumConflicts();
-    }
+        return decisions.get(displayedKeys.get(row));
+    }
+
+    /**
+     * Sets whether all tags or only tags with conflicts are displayed
+     * 
+     * @param showTagsWithConflictsOnly if true, only tags with conflicts are displayed
+     */
+    public void setShowTagsWithConflictsOnly(boolean showTagsWithConflictsOnly) {
+        this.showTagsWithConflictsOnly = showTagsWithConflictsOnly;
+        rebuild();
+    }
+
+    /**
+     * Prepare the default decisions for the current model
+     * 
+     */
+    public void prepareDefaultTagDecisions() {
+        for (MultiValueResolutionDecision decision: decisions.values()) {
+            List<String> values = decision.getValues();
+            values.remove("");
+            if (values.size() == 1) {
+                decision.keepOne(values.get(0));
+            } else {
+                decision.keepAll();
+            }
+        }
+        rebuild();
+    }
+
 }
Index: trunk/src/org/openstreetmap/josm/gui/conflict/tags/TagConflictResolverTable.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/conflict/tags/TagConflictResolverTable.java	(revision 2219)
+++ trunk/src/org/openstreetmap/josm/gui/conflict/tags/TagConflictResolverTable.java	(revision 2220)
@@ -6,4 +6,5 @@
 
 import javax.swing.AbstractAction;
+import javax.swing.JComboBox;
 import javax.swing.JComponent;
 import javax.swing.JTable;
@@ -39,4 +40,6 @@
 
         ((MultiValueCellEditor)getColumnModel().getColumn(2).getCellEditor()).addNavigationListeners(this);
+
+        setRowHeight((int)new JComboBox().getPreferredSize().getHeight());
     }
 
