diff --git a/src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java b/src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java
index be435fc..77a0643 100644
--- a/src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java
+++ b/src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java
@@ -78,6 +78,7 @@ import org.openstreetmap.josm.gui.dialogs.relation.actions.OKAction;
 import org.openstreetmap.josm.gui.dialogs.relation.actions.PasteMembersAction;
 import org.openstreetmap.josm.gui.dialogs.relation.actions.RemoveAction;
 import org.openstreetmap.josm.gui.dialogs.relation.actions.RemoveSelectedAction;
+import org.openstreetmap.josm.gui.dialogs.relation.actions.RefreshAction;
 import org.openstreetmap.josm.gui.dialogs.relation.actions.ReverseAction;
 import org.openstreetmap.josm.gui.dialogs.relation.actions.SelectPrimitivesForSelectedMembersAction;
 import org.openstreetmap.josm.gui.dialogs.relation.actions.SelectedMembersForSelectionAction;
@@ -127,6 +128,14 @@ public class GenericRelationEditor extends RelationEditor  {
      */
     private JButton sortBelowButton;
     /**
+     * Action for performing the {@link RefreshAction}
+     */
+    private RefreshAction refreshAction;
+    /**
+     * Action for performing the {@link ApplyAction}
+     */
+    private ApplyAction applyAction;
+    /**
      * Action for performing the {@link CancelAction}
      */
     private CancelAction cancelAction;
@@ -171,21 +180,7 @@ public class GenericRelationEditor extends RelationEditor  {
         referrerModel = new ReferringRelationsBrowserModel(relation);
 
         tagEditorPanel = new TagEditorPanel(relation, presetHandler);
-
-        // populate the models
-        //
-        if (relation != null) {
-            tagEditorPanel.getModel().initFromPrimitive(relation);
-            this.memberTableModel.populate(relation);
-            if (!getLayer().data.getRelations().contains(relation)) {
-                // treat it as a new relation if it doesn't exist in the
-                // data set yet.
-                setRelation(null);
-            }
-        } else {
-            tagEditorPanel.getModel().clear();
-            this.memberTableModel.populate(null);
-        }
+        populateModels(relation);
         tagEditorPanel.getModel().ensureOneTag();
 
         JSplitPane pane = buildSplitPane();
@@ -258,7 +253,32 @@ public class GenericRelationEditor extends RelationEditor  {
         HelpUtil.setHelpContext(getRootPane(), ht("/Dialog/RelationEditor"));
     }
 
-    protected void cancel() {
+    public void reloadDataFromRelation() {
+        setRelation(getRelation());
+        populateModels(getRelation());
+        refreshAction.updateEnabledState();
+    }
+
+    private void populateModels(Relation relation) {
+        if (relation != null) {
+            tagEditorPanel.getModel().initFromPrimitive(relation);
+            this.memberTableModel.populate(relation);
+            if (!getLayer().data.getRelations().contains(relation)) {
+                // treat it as a new relation if it doesn't exist in the
+                // data set yet.
+                setRelation(null);
+            }
+        } else {
+            tagEditorPanel.getModel().clear();
+            this.memberTableModel.populate(null);
+        }
+    }
+
+    public void apply() {
+        applyAction.actionPerformed(null);
+    }
+
+    public void cancel() {
         cancelAction.actionPerformed(null);
     }
 
@@ -270,7 +290,8 @@ public class GenericRelationEditor extends RelationEditor  {
     protected JToolBar buildToolBar() {
         JToolBar tb  = new JToolBar();
         tb.setFloatable(false);
-        tb.add(new ApplyAction(memberTable, memberTableModel, tagEditorPanel.getModel(), getLayer(), this));
+        tb.add(refreshAction = new RefreshAction(memberTable, memberTableModel, tagEditorPanel.getModel(), getLayer(), this));
+        tb.add(applyAction = new ApplyAction(memberTable, memberTableModel, tagEditorPanel.getModel(), getLayer(), this));
         tb.add(new DuplicateRelationAction(memberTableModel, tagEditorPanel.getModel(), getLayer()));
         DeleteCurrentRelationAction deleteAction = new DeleteCurrentRelationAction(getLayer(), this);
         addPropertyChangeListener(deleteAction);
diff --git a/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableModel.java b/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableModel.java
index 06bad08..cd6a190 100644
--- a/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableModel.java
+++ b/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableModel.java
@@ -234,9 +234,12 @@ implements TableModelListener, SelectionChangedListener, DataSetListener, OsmPri
             return;
         }
         RelationMember member = members.get(rowIndex);
-        RelationMember newMember = new RelationMember(value.toString(), member.getMember());
+        String role = value.toString();
+        if (member.hasRole(role)) return;
+        RelationMember newMember = new RelationMember(role, member.getMember());
         members.remove(rowIndex);
         members.add(rowIndex, newMember);
+        fireTableDataChanged();
     }
 
     @Override
diff --git a/src/org/openstreetmap/josm/gui/dialogs/relation/actions/ApplyAction.java b/src/org/openstreetmap/josm/gui/dialogs/relation/actions/ApplyAction.java
index 0e68e10..3777829 100644
--- a/src/org/openstreetmap/josm/gui/dialogs/relation/actions/ApplyAction.java
+++ b/src/org/openstreetmap/josm/gui/dialogs/relation/actions/ApplyAction.java
@@ -3,9 +3,15 @@ package org.openstreetmap.josm.gui.dialogs.relation.actions;
 
 import static org.openstreetmap.josm.tools.I18n.tr;
 
-import java.awt.Component;
 import java.awt.event.ActionEvent;
 
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+
+import javax.swing.event.TableModelEvent;
+import javax.swing.event.TableModelListener;
+
+import org.openstreetmap.josm.gui.dialogs.relation.GenericRelationEditor;
 import org.openstreetmap.josm.gui.dialogs.relation.MemberTable;
 import org.openstreetmap.josm.gui.dialogs.relation.MemberTableModel;
 import org.openstreetmap.josm.gui.dialogs.relation.RelationAware;
@@ -17,7 +23,7 @@ import org.openstreetmap.josm.tools.ImageProvider;
  * Apply the current updates.
  * @since 9496
  */
-public class ApplyAction extends SavingAction {
+public class ApplyAction extends SavingAction implements PropertyChangeListener, TableModelListener {
 
     /**
      * Constructs a new {@code ApplyAction}.
@@ -33,28 +39,30 @@ public class ApplyAction extends SavingAction {
         putValue(SHORT_DESCRIPTION, tr("Apply the current updates"));
         putValue(SMALL_ICON, ImageProvider.get("save"));
         putValue(NAME, tr("Apply"));
-        setEnabled(true);
+        updateEnabledState();
+        memberTableModel.addTableModelListener(this);
+        tagModel.addPropertyChangeListener(this);
     }
 
     @Override
     public void actionPerformed(ActionEvent e) {
-        if (editor.getRelation() == null) {
-            applyNewRelation(tagModel);
-        } else if (!memberTableModel.hasSameMembersAs(editor.getRelationSnapshot()) || tagModel.isDirty()) {
-            if (editor.isDirtyRelation()) {
-                if (confirmClosingBecauseOfDirtyState()) {
-                    if (layer.getConflicts().hasConflictForMy(editor.getRelation())) {
-                        warnDoubleConflict();
-                        return;
-                    }
-                    applyExistingConflictingRelation(tagModel);
-                    if (editor instanceof Component) {
-                        ((Component) editor).setVisible(false);
-                    }
-                }
-            } else {
-                applyExistingNonConflictingRelation(tagModel);
-            }
+        if (applyChanges()) {
+            ((GenericRelationEditor) editor).reloadDataFromRelation();
         }
     }
+
+    @Override
+    protected void updateEnabledState() {
+        setEnabled(isEditorDirty());
+    }
+
+    @Override
+    public void propertyChange(PropertyChangeEvent evt) {
+        updateEnabledState();
+    }
+
+    @Override
+    public void tableChanged(TableModelEvent e) {
+        updateEnabledState();
+    }
 }
diff --git a/src/org/openstreetmap/josm/gui/dialogs/relation/actions/CancelAction.java b/src/org/openstreetmap/josm/gui/dialogs/relation/actions/CancelAction.java
index 980d5a5..8632285 100644
--- a/src/org/openstreetmap/josm/gui/dialogs/relation/actions/CancelAction.java
+++ b/src/org/openstreetmap/josm/gui/dialogs/relation/actions/CancelAction.java
@@ -3,7 +3,6 @@ package org.openstreetmap.josm.gui.dialogs.relation.actions;
 
 import static org.openstreetmap.josm.tools.I18n.tr;
 
-import java.awt.Component;
 import java.awt.event.ActionEvent;
 
 import javax.swing.JComponent;
@@ -65,29 +64,12 @@ public class CancelAction extends SavingAction {
             if (ret == 0) { //Yes, save the changes
                 //copied from OKAction.run()
                 Main.pref.put("relation.editor.generic.lastrole", tfRole.getText());
-                if (editor.getRelation() == null) {
-                    applyNewRelation(tagModel);
-                } else if (!memberTableModel.hasSameMembersAs(snapshot) || tagModel.isDirty()) {
-                    if (editor.isDirtyRelation()) {
-                        if (confirmClosingBecauseOfDirtyState()) {
-                            if (layer.getConflicts().hasConflictForMy(editor.getRelation())) {
-                                warnDoubleConflict();
-                                return;
-                            }
-                            applyExistingConflictingRelation(tagModel);
-                        } else
-                            return;
-                    } else {
-                        applyExistingNonConflictingRelation(tagModel);
-                    }
-                }
+                if (!applyChanges()) return;
             } else if (ret == 2 || ret == JOptionPane.CLOSED_OPTION) //Cancel, continue editing
                 return;
             //in case of "No, discard", there is no extra action to be performed here.
         }
-        if (editor instanceof Component) {
-            ((Component) editor).setVisible(false);
-        }
+        hideEditor();
     }
 
     protected int confirmClosingByCancel() {
diff --git a/src/org/openstreetmap/josm/gui/dialogs/relation/actions/OKAction.java b/src/org/openstreetmap/josm/gui/dialogs/relation/actions/OKAction.java
index 0cc65f3..5df5c69 100644
--- a/src/org/openstreetmap/josm/gui/dialogs/relation/actions/OKAction.java
+++ b/src/org/openstreetmap/josm/gui/dialogs/relation/actions/OKAction.java
@@ -3,7 +3,6 @@ package org.openstreetmap.josm.gui.dialogs.relation.actions;
 
 import static org.openstreetmap.josm.tools.I18n.tr;
 
-import java.awt.Component;
 import java.awt.event.ActionEvent;
 
 import org.openstreetmap.josm.Main;
@@ -42,24 +41,7 @@ public class OKAction extends SavingAction {
     public void actionPerformed(ActionEvent e) {
         Main.pref.put("relation.editor.generic.lastrole", tfRole.getText());
         memberTable.stopHighlighting();
-        if (editor.getRelation() == null) {
-            applyNewRelation(tagModel);
-        } else if (!memberTableModel.hasSameMembersAs(editor.getRelationSnapshot()) || tagModel.isDirty()) {
-            if (editor.isDirtyRelation()) {
-                if (confirmClosingBecauseOfDirtyState()) {
-                    if (layer.getConflicts().hasConflictForMy(editor.getRelation())) {
-                        warnDoubleConflict();
-                        return;
-                    }
-                    applyExistingConflictingRelation(tagModel);
-                } else
-                    return;
-            } else {
-                applyExistingNonConflictingRelation(tagModel);
-            }
-        }
-        if (editor instanceof Component) {
-            ((Component) editor).setVisible(false);
-        }
+        if (!applyChanges()) return;
+        hideEditor();
     }
 }
diff --git a/src/org/openstreetmap/josm/gui/dialogs/relation/actions/RefreshAction.java b/src/org/openstreetmap/josm/gui/dialogs/relation/actions/RefreshAction.java
new file mode 100644
index 0000000..5734311
--- /dev/null
+++ b/src/org/openstreetmap/josm/gui/dialogs/relation/actions/RefreshAction.java
@@ -0,0 +1,141 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.dialogs.relation.actions;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.Component;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+
+import javax.swing.JComponent;
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.osm.Relation;
+import org.openstreetmap.josm.gui.dialogs.relation.GenericRelationEditor;
+import org.openstreetmap.josm.gui.dialogs.relation.MemberTable;
+import org.openstreetmap.josm.gui.dialogs.relation.MemberTableModel;
+import org.openstreetmap.josm.gui.dialogs.relation.RelationAware;
+import org.openstreetmap.josm.gui.HelpAwareOptionPane;
+import org.openstreetmap.josm.gui.HelpAwareOptionPane.ButtonSpec;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer;
+import org.openstreetmap.josm.gui.layer.OsmDataLayer.CommandQueueListener;
+import org.openstreetmap.josm.gui.tagging.TagEditorModel;
+import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.Shortcut;
+
+/**
+ * Refresh relation.
+ */
+public class RefreshAction extends SavingAction implements CommandQueueListener {
+
+    /**
+     * Constructs a new {@code ApplyAction}.
+     * @param memberTable member table
+     * @param memberTableModel member table model
+     * @param layer OSM data layer
+     * @param editor relation editor
+     * @param tagModel tag editor model
+     */
+    public RefreshAction(MemberTable memberTable, MemberTableModel memberTableModel, TagEditorModel tagModel, OsmDataLayer layer,
+            RelationAware editor) {
+        super(memberTable, memberTableModel, tagModel, layer, editor, null);
+        Shortcut sc = Shortcut.registerShortcut("relationeditor:refresh", tr("Relation Editor: Refresh"), KeyEvent.CHAR_UNDEFINED, Shortcut.NONE);
+        putValue(SHORT_DESCRIPTION, Main.platform.makeTooltip(tr("Refresh relation from data layer"), sc));
+        putValue(SMALL_ICON, ImageProvider.get("dialogs/refresh"));
+        putValue(NAME, tr("Refresh"));
+        getEditor().getRootPane().getActionMap().put("refresh", this);
+        getEditor().getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(sc.getKeyStroke(), "refresh");
+        Main.main.undoRedo.addCommandQueueListener(this);
+        updateEnabledState();
+    }
+
+    private GenericRelationEditor getEditor() {
+        return (GenericRelationEditor) editor;
+    }
+
+    @Override
+    public void actionPerformed(ActionEvent e) {
+        Relation relation = editor.getRelation();
+        if (relation == null) return;
+        if (relation.isDeleted()) {
+            if (confirmCloseDeletedRelation() == 0) {
+                hideEditor();
+            }
+            return;
+        }
+        if (isEditorDirty() && confirmDiscardDirtyData() != 0) return;
+        getEditor().reloadDataFromRelation();
+    }
+
+    @Override
+    public void updateEnabledState() {
+        Relation relation = editor.getRelation();
+        Relation snapshot = editor.getRelationSnapshot();
+        setEnabled(snapshot != null && (
+            !relation.hasEqualTechnicalAttributes(snapshot) ||
+            !relation.hasEqualSemanticAttributes(snapshot)
+        ));
+    }
+
+    protected int confirmDiscardDirtyData() {
+        ButtonSpec[] options = new ButtonSpec[] {
+                new ButtonSpec(
+                        tr("Yes, discard changes and reload"),
+                        ImageProvider.get("ok"),
+                        tr("Click to discard the changes and reload data from layer"),
+                        null /* no specific help topic */
+                ),
+                new ButtonSpec(
+                        tr("Cancel, continue editing"),
+                        ImageProvider.get("cancel"),
+                        tr("Click to return to the relation editor and to resume relation editing"),
+                        null /* no specific help topic */
+                )
+        };
+
+        return HelpAwareOptionPane.showOptionDialog(
+                Main.parent,
+                tr("<html>You have unsaved changes in this editor window.<br><br>Do you want to discard these changes and reload data from layer?</html>"),
+                        tr("Unsaved changes"),
+                        JOptionPane.WARNING_MESSAGE,
+                        null,
+                        options,
+                        options[1], // Cancel is default
+                        "/Dialog/RelationEditor#Reload"
+        );
+    }
+
+    protected int confirmCloseDeletedRelation() {
+        ButtonSpec[] options = new ButtonSpec[] {
+                new ButtonSpec(
+                        tr("Yes"),
+                        ImageProvider.get("ok"),
+                        tr("Click to close window"),
+                        null /* no specific help topic */
+                ),
+                new ButtonSpec(
+                        tr("No, continue editing"),
+                        ImageProvider.get("cancel"),
+                        tr("Click to return to the relation editor and to resume relation editing"),
+                        null /* no specific help topic */
+                )
+        };
+
+        return HelpAwareOptionPane.showOptionDialog(
+                Main.parent,
+                tr("<html>Relation has been deleted outside editor.<br><br>Do you want to close this window?</html>"),
+                        tr("Deleted relation"),
+                        JOptionPane.WARNING_MESSAGE,
+                        null,
+                        options,
+                        options[0], // Yes is default
+                        "/Dialog/RelationEditor#Reload"
+        );
+    }
+
+    @Override
+    public void commandChanged(int queueSize, int redoSize) {
+        updateEnabledState();
+    }
+}
diff --git a/src/org/openstreetmap/josm/gui/dialogs/relation/actions/SavingAction.java b/src/org/openstreetmap/josm/gui/dialogs/relation/actions/SavingAction.java
index e7525d2..96c51af 100644
--- a/src/org/openstreetmap/josm/gui/dialogs/relation/actions/SavingAction.java
+++ b/src/org/openstreetmap/josm/gui/dialogs/relation/actions/SavingAction.java
@@ -3,6 +3,7 @@ package org.openstreetmap.josm.gui.dialogs.relation.actions;
 
 import static org.openstreetmap.josm.tools.I18n.tr;
 
+import java.awt.Component;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -110,9 +111,6 @@ abstract class SavingAction extends AbstractRelationEditorAction {
         memberTableModel.applyToRelation(editedRelation);
         Main.main.undoRedo.add(new ChangeCommand(editor.getRelation(), editedRelation));
         layer.data.fireSelectionChanged();
-        // this will refresh the snapshot and update the dialog title
-        //
-        editor.setRelation(editor.getRelation());
     }
 
     protected boolean confirmClosingBecauseOfDirtyState() {
@@ -165,4 +163,37 @@ abstract class SavingAction extends AbstractRelationEditorAction {
     protected void updateEnabledState() {
         // Do nothing
     }
+
+    protected boolean applyChanges() {
+        if (editor.getRelation() == null) {
+            applyNewRelation(tagModel);
+        } else if (isEditorDirty()) {
+            if (editor.isDirtyRelation()) {
+                if (confirmClosingBecauseOfDirtyState()) {
+                    if (layer.getConflicts().hasConflictForMy(editor.getRelation())) {
+                        warnDoubleConflict();
+                        return false;
+                    }
+                    applyExistingConflictingRelation(tagModel);
+                    hideEditor();
+                } else
+                    return false;
+            } else {
+                applyExistingNonConflictingRelation(tagModel);
+            }
+        }
+        editor.setRelation(editor.getRelation());
+        return true;
+    }
+
+    protected void hideEditor() {
+        if (editor instanceof Component) {
+            ((Component) editor).setVisible(false);
+        }
+    }
+
+    protected boolean isEditorDirty() {
+        Relation snapshot = editor.getRelationSnapshot();
+        return (snapshot != null && !memberTableModel.hasSameMembersAs(snapshot)) || tagModel.isDirty();
+    }
 }
diff --git a/src/org/openstreetmap/josm/gui/tagging/TagEditorModel.java b/src/org/openstreetmap/josm/gui/tagging/TagEditorModel.java
index 6ad4926..954f42c 100644
--- a/src/org/openstreetmap/josm/gui/tagging/TagEditorModel.java
+++ b/src/org/openstreetmap/josm/gui/tagging/TagEditorModel.java
@@ -165,9 +165,12 @@ public class TagEditorModel extends AbstractTableModel {
      * removes all tags in the model
      */
     public void clear() {
+        boolean wasEmpty = tags.isEmpty();
         tags.clear();
-        setDirty(true);
-        fireTableDataChanged();
+        if (!wasEmpty) {
+            setDirty(true);
+            fireTableDataChanged();
+        }
     }
 
     /**
@@ -334,7 +337,6 @@ public class TagEditorModel extends AbstractTableModel {
         TagModel tag = new TagModel();
         tags.add(tag);
         fireTableDataChanged();
-        setDirty(true);
     }
 
     /**
