Index: trunk/src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java	(revision 1821)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/relation/GenericRelationEditor.java	(revision 1822)
@@ -39,5 +39,4 @@
 import javax.swing.JTextField;
 import javax.swing.KeyStroke;
-import javax.swing.ListSelectionModel;
 import javax.swing.SwingUtilities;
 import javax.swing.event.DocumentEvent;
@@ -73,20 +72,18 @@
 import org.xml.sax.SAXException;
 
-
 /**
  * This dialog is for editing relations.
- *
- * In the basic form, it provides two tables, one with the relation tags
- * and one with the relation members. (Relation tags can be edited through
- * the normal properties dialog as well, if you manage to get a relation
- * selected!)
- *
+ * 
+ * In the basic form, it provides two tables, one with the relation tags and one with the relation
+ * members. (Relation tags can be edited through the normal properties dialog as well, if you manage
+ * to get a relation selected!)
+ * 
  * @author Frederik Ramm <frederik@remote.org>
- *
+ * 
  */
 public class GenericRelationEditor extends RelationEditor {
 
     static private final Logger logger = Logger.getLogger(GenericRelationEditor.class.getName());
-    static private final Dimension DEFAULT_EDITOR_DIMENSION = new Dimension(700,500);
+    static private final Dimension DEFAULT_EDITOR_DIMENSION = new Dimension(700, 500);
 
     /** the tag table and its model */
@@ -107,15 +104,14 @@
 
     /**
-     * Creates a new relation editor for the given relation. The relation
-     * will be saved if the user selects "ok" in the editor.
-     *
+     * Creates a new relation editor for the given relation. The relation will be saved if the user
+     * selects "ok" in the editor.
+     * 
      * If no relation is given, will create an editor for a new relation.
-     *
+     * 
      * @param layer the {@see OsmDataLayer} the new or edited relation belongs to
      * @param relation relation to edit, or null to create a new one.
      * @param selectedMembers a collection of members which shall be selected initially
      */
-    public GenericRelationEditor(OsmDataLayer layer, Relation relation, Collection<RelationMember> selectedMembers )
-    {
+    public GenericRelationEditor(OsmDataLayer layer, Relation relation, Collection<RelationMember> selectedMembers) {
         super(layer, relation, selectedMembers);
 
@@ -149,5 +145,5 @@
         JPanel pnl = new JPanel();
         pnl.setLayout(new BorderLayout());
-        pnl.add(pane,BorderLayout.CENTER);
+        pnl.add(pane, BorderLayout.CENTER);
         pnl.setBorder(BorderFactory.createRaisedBevelBorder());
 
@@ -159,5 +155,5 @@
         }
 
-        getContentPane().add(tabbedPane,BorderLayout.CENTER);
+        getContentPane().add(tabbedPane, BorderLayout.CENTER);
         getContentPane().add(buildOkCancelButtonPanel(), BorderLayout.SOUTH);
 
@@ -165,13 +161,14 @@
         try {
             setAlwaysOnTop(true);
-        } catch(SecurityException e) {
-            logger.warning(tr("Caught security exception for setAlwaysOnTop(). Ignoring. Exception was: {0}", e.toString()));
-        }
-    }
-
-    /**
-     * builds the panel with the OK and  the Cancel button
-     *
-     * @return the panel with the OK and  the Cancel button
+        } catch (SecurityException e) {
+            logger.warning(tr("Caught security exception for setAlwaysOnTop(). Ignoring. Exception was: {0}", e
+                    .toString()));
+        }
+    }
+
+    /**
+     * builds the panel with the OK and the Cancel button
+     * 
+     * @return the panel with the OK and the Cancel button
      */
     protected JPanel buildOkCancelButtonPanel() {
@@ -187,5 +184,5 @@
     /**
      * build the panel with the buttons on the left
-     *
+     * 
      * @return
      */
@@ -197,7 +194,7 @@
         gc.gridx = 0;
         gc.gridy = 0;
-        gc.gridheight  =1;
+        gc.gridheight = 1;
         gc.gridwidth = 1;
-        gc.insets = new Insets(0,5,0,5);
+        gc.insets = new Insets(0, 5, 0, 5);
         gc.fill = GridBagConstraints.HORIZONTAL;
         gc.anchor = GridBagConstraints.CENTER;
@@ -220,5 +217,5 @@
         gc.weighty = 1.0;
         gc.fill = GridBagConstraints.BOTH;
-        pnl.add(new JPanel(),gc);
+        pnl.add(new JPanel(), gc);
         return pnl;
     }
@@ -226,5 +223,5 @@
     /**
      * builds the panel with the tag editor
-     *
+     * 
      * @return the panel with the tag editor
      */
@@ -237,8 +234,8 @@
         tagTable = new TagTable(tagEditorModel);
         acCache.initFromJOSMDataset();
-        TagCellEditor editor = ((TagCellEditor)tagTable.getColumnModel().getColumn(0).getCellEditor());
+        TagCellEditor editor = ((TagCellEditor) tagTable.getColumnModel().getColumn(0).getCellEditor());
         editor.setAutoCompletionCache(acCache);
         editor.setAutoCompletionList(acList);
-        editor = ((TagCellEditor)tagTable.getColumnModel().getColumn(1).getCellEditor());
+        editor = ((TagCellEditor) tagTable.getColumnModel().getColumn(1).getCellEditor());
         editor.setAutoCompletionCache(acCache);
         editor.setAutoCompletionList(acList);
@@ -250,18 +247,17 @@
         // getPreferredViewportSize() in JTable, but did not work.
         //
-        scrollPane.addComponentListener(
-                new ComponentAdapter() {
-                    @Override public void componentResized(ComponentEvent e) {
-                        super.componentResized(e);
-                        Dimension d = scrollPane.getViewport().getExtentSize();
-                        tagTable.adjustColumnWidth(d.width);
-                    }
-                }
-        );
+        scrollPane.addComponentListener(new ComponentAdapter() {
+            @Override
+            public void componentResized(ComponentEvent e) {
+                super.componentResized(e);
+                Dimension d = scrollPane.getViewport().getExtentSize();
+                tagTable.adjustColumnWidth(d.width);
+            }
+        });
 
         GridBagConstraints gc = new GridBagConstraints();
         gc.gridx = 0;
         gc.gridy = 0;
-        gc.gridheight  =1;
+        gc.gridheight = 1;
         gc.gridwidth = 3;
         gc.fill = GridBagConstraints.HORIZONTAL;
@@ -273,5 +269,5 @@
         gc.gridx = 0;
         gc.gridy = 1;
-        gc.gridheight  =1;
+        gc.gridheight = 1;
         gc.gridwidth = 1;
         gc.fill = GridBagConstraints.VERTICAL;
@@ -293,5 +289,5 @@
     /**
      * builds the panel for the relation member editor
-     *
+     * 
      * @return the panel for the relation member editor
      */
@@ -310,18 +306,17 @@
         // getPreferredViewportSize() in JTable, but did not work.
         //
-        scrollPane.addComponentListener(
-                new ComponentAdapter() {
-                    @Override public void componentResized(ComponentEvent e) {
-                        super.componentResized(e);
-                        Dimension d = scrollPane.getViewport().getExtentSize();
-                        memberTable.adjustColumnWidth(d.width);
-                    }
-                }
-        );
+        scrollPane.addComponentListener(new ComponentAdapter() {
+            @Override
+            public void componentResized(ComponentEvent e) {
+                super.componentResized(e);
+                Dimension d = scrollPane.getViewport().getExtentSize();
+                memberTable.adjustColumnWidth(d.width);
+            }
+        });
 
         GridBagConstraints gc = new GridBagConstraints();
         gc.gridx = 0;
         gc.gridy = 0;
-        gc.gridheight  =1;
+        gc.gridheight = 1;
         gc.gridwidth = 3;
         gc.fill = GridBagConstraints.HORIZONTAL;
@@ -333,5 +328,5 @@
         gc.gridx = 0;
         gc.gridy = 1;
-        gc.gridheight  =1;
+        gc.gridheight = 1;
         gc.gridwidth = 1;
         gc.fill = GridBagConstraints.VERTICAL;
@@ -354,5 +349,5 @@
         gc.gridx = 0;
         gc.gridy = 0;
-        gc.gridheight  =1;
+        gc.gridheight = 1;
         gc.gridwidth = 3;
         gc.fill = GridBagConstraints.HORIZONTAL;
@@ -364,5 +359,5 @@
         gc.gridx = 0;
         gc.gridy = 1;
-        gc.gridheight  =1;
+        gc.gridheight = 1;
         gc.gridwidth = 1;
         gc.fill = GridBagConstraints.VERTICAL;
@@ -379,18 +374,16 @@
         pnl2.add(buildSelectionTablePanel(), gc);
 
-        final JSplitPane splitPane = new  JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
+        final JSplitPane splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
         splitPane.setLeftComponent(pnl);
         splitPane.setRightComponent(pnl2);
         splitPane.setOneTouchExpandable(false);
-        addWindowListener(
-                new WindowAdapter() {
-                    @Override
-                    public void windowOpened(WindowEvent e) {
-                        // has to be called when the window is visible, otherwise
-                        // no effect
-                        splitPane.setDividerLocation(0.6);
-                    }
-                }
-        );
+        addWindowListener(new WindowAdapter() {
+            @Override
+            public void windowOpened(WindowEvent e) {
+                // has to be called when the window is visible, otherwise
+                // no effect
+                splitPane.setDividerLocation(0.6);
+            }
+        });
 
         JPanel pnl3 = new JPanel();
@@ -403,5 +396,5 @@
     /**
      * builds the panel with the table displaying the currently selected primitives
-     *
+     * 
      * @return
      */
@@ -409,5 +402,5 @@
         JPanel pnl = new JPanel();
         pnl.setLayout(new BorderLayout());
-        JTable tbl = new JTable(selectionTableModel,new SelectionTableColumnModel(memberTableModel));
+        JTable tbl = new JTable(selectionTableModel, new SelectionTableColumnModel(memberTableModel));
         tbl.setEnabled(false);
         JScrollPane pane = new JScrollPane(tbl);
@@ -417,7 +410,6 @@
 
     /**
-     * builds the {@see JSplitPane} which divides the editor in an upper and a lower
-     * half
-     *
+     * builds the {@see JSplitPane} which divides the editor in an upper and a lower half
+     * 
      * @return the split panel
      */
@@ -427,14 +419,12 @@
         pane.setBottomComponent(buildMemberEditorPanel());
         pane.setOneTouchExpandable(true);
-        addWindowListener(
-                new WindowAdapter() {
-                    @Override
-                    public void windowOpened(WindowEvent e) {
-                        // has to be called when the window is visible, otherwise
-                        // no effect
-                        pane.setDividerLocation(0.3);
-                    }
-                }
-        );
+        addWindowListener(new WindowAdapter() {
+            @Override
+            public void windowOpened(WindowEvent e) {
+                // has to be called when the window is visible, otherwise
+                // no effect
+                pane.setDividerLocation(0.3);
+            }
+        });
         return pane;
     }
@@ -442,5 +432,5 @@
     /**
      * build the panel with the buttons on the left
-     *
+     * 
      * @return
      */
@@ -452,7 +442,7 @@
         gc.gridx = 0;
         gc.gridy = 0;
-        gc.gridheight  =1;
+        gc.gridheight = 1;
         gc.gridwidth = 1;
-        gc.insets = new Insets(0,5,0,5);
+        gc.insets = new Insets(0, 5, 0, 5);
         gc.fill = GridBagConstraints.HORIZONTAL;
         gc.anchor = GridBagConstraints.CENTER;
@@ -473,12 +463,17 @@
         RemoveAction removeSelectedAction = new RemoveAction();
         memberTable.getSelectionModel().addListSelectionListener(removeSelectedAction);
-        pnl.add(new JButton(removeSelectedAction),gc);
+        pnl.add(new JButton(removeSelectedAction), gc);
+
+        // ------
+        gc.gridy = 3;
+        SortAction sortAction = new SortAction();
+        pnl.add(new JButton(sortAction), gc);
 
         // ------
         // just grab the remaining space
-        gc.gridy = 3;
+        gc.gridy = 4;
         gc.weighty = 1.0;
         gc.fill = GridBagConstraints.BOTH;
-        pnl.add(new JPanel(),gc);
+        pnl.add(new JPanel(), gc);
         return pnl;
     }
@@ -486,5 +481,5 @@
     /**
      * build the panel with the buttons for adding or removing the current selection
-     *
+     * 
      * @return
      */
@@ -496,7 +491,7 @@
         gc.gridx = 0;
         gc.gridy = 0;
-        gc.gridheight  =1;
+        gc.gridheight = 1;
         gc.gridwidth = 1;
-        gc.insets = new Insets(0,5,0,5);
+        gc.insets = new Insets(0, 5, 0, 5);
         gc.fill = GridBagConstraints.HORIZONTAL;
         gc.anchor = GridBagConstraints.CENTER;
@@ -538,5 +533,5 @@
         gc.weighty = 1.0;
         gc.fill = GridBagConstraints.BOTH;
-        pnl.add(new JPanel(),gc);
+        pnl.add(new JPanel(), gc);
 
         return pnl;
@@ -552,12 +547,10 @@
         buttonPanel.add(new JLabel(tr("Role:")));
         tfRole = new JTextField(10);
-        tfRole.addFocusListener(
-                new FocusAdapter() {
-                    @Override
-                    public void focusGained(FocusEvent e) {
-                        tfRole.selectAll();
-                    }
-                }
-        );
+        tfRole.addFocusListener(new FocusAdapter() {
+            @Override
+            public void focusGained(FocusEvent e) {
+                tfRole.selectAll();
+            }
+        });
         buttonPanel.add(tfRole);
         SetRoleAction setRoleAction = new SetRoleAction();
@@ -566,5 +559,5 @@
         tfRole.getDocument().addDocumentListener(setRoleAction);
 
-        //--- copy relation action
+        // --- copy relation action
         buttonPanel.add(new SideButton(new DuplicateRelationAction()));
 
@@ -580,8 +573,8 @@
      */
     protected void applyChanges() {
-        if (getRelation()== null) {
+        if (getRelation() == null) {
             // If the user wanted to create a new relation, but hasn't added any members or
             // tags, don't add an empty relation
-            if(memberTableModel.getRowCount() == 0 && tagEditorModel.getKeys().isEmpty())
+            if (memberTableModel.getRowCount() == 0 && tagEditorModel.getKeys().isEmpty())
                 return;
             Relation newRelation = new Relation();
@@ -590,5 +583,5 @@
             Main.main.undoRedo.add(new AddCommand(newRelation));
             DataSet.fireSelectionChanged(getLayer().data.getSelected());
-        } else if (! memberTableModel.hasSameMembersAs(getRelation()) || tagEditorModel.isDirty()) {
+        } else if (!memberTableModel.hasSameMembersAs(getRelation()) || tagEditorModel.isDirty()) {
             Relation editedRelation = new Relation(getRelation());
             tagEditorModel.applyToPrimitive(editedRelation);
@@ -597,10 +590,7 @@
                 Conflict<Relation> conflict = new Conflict<Relation>(getRelation(), editedRelation);
                 getLayer().getConflicts().add(conflict);
-                JOptionPane op = new JOptionPane(
-                        tr("<html>The relation has changed outside of the editor.<br>"
-                                + "Your edit can't be applied directly, a conflict has been created instead.</html>"
-                        ),
-                        JOptionPane.WARNING_MESSAGE
-                );
+                JOptionPane op = new JOptionPane(tr("<html>The relation has changed outside of the editor.<br>"
+                        + "Your edit can't be applied directly, a conflict has been created instead.</html>"),
+                        JOptionPane.WARNING_MESSAGE);
                 JDialog dialog = op.createDialog(this, tr("Conflict created"));
                 dialog.setAlwaysOnTop(true);
@@ -626,5 +616,5 @@
     /**
      * Asynchronously download the members of the currently edited relation
-     *
+     * 
      */
     private void downloadRelationMembers() {
@@ -650,12 +640,13 @@
     class AddSelectedAtStartAction extends AbstractAction implements TableModelListener {
         public AddSelectedAtStartAction() {
-            putValue(SHORT_DESCRIPTION,  tr("Add all primitives selected in the current dataset before the first member"));
+            putValue(SHORT_DESCRIPTION,
+                    tr("Add all primitives selected in the current dataset before the first member"));
             putValue(SMALL_ICON, ImageProvider.get("dialogs/conflict", "copystartright"));
-            //putValue(NAME, tr("Add Selected"));
+            // putValue(NAME, tr("Add Selected"));
             refreshEnabled();
         }
 
         protected void refreshEnabled() {
-            setEnabled(selectionTableModel.getRowCount() >  0);
+            setEnabled(selectionTableModel.getRowCount() > 0);
         }
 
@@ -671,12 +662,12 @@
     class AddSelectedAtEndAction extends AbstractAction implements TableModelListener {
         public AddSelectedAtEndAction() {
-            putValue(SHORT_DESCRIPTION,  tr("Add all primitives selected in the current dataset after the last member"));
+            putValue(SHORT_DESCRIPTION, tr("Add all primitives selected in the current dataset after the last member"));
             putValue(SMALL_ICON, ImageProvider.get("dialogs/conflict", "copyendright"));
-            //putValue(NAME, tr("Add Selected"));
+            // putValue(NAME, tr("Add Selected"));
             refreshEnabled();
         }
 
         protected void refreshEnabled() {
-            setEnabled(selectionTableModel.getRowCount() >  0);
+            setEnabled(selectionTableModel.getRowCount() > 0);
         }
 
@@ -692,17 +683,19 @@
     class AddSelectedBeforeSelection extends AbstractAction implements TableModelListener, ListSelectionListener {
         public AddSelectedBeforeSelection() {
-            putValue(SHORT_DESCRIPTION,  tr("Add all primitives selected in the current dataset before the first selected member"));
+            putValue(SHORT_DESCRIPTION,
+                    tr("Add all primitives selected in the current dataset before the first selected member"));
             putValue(SMALL_ICON, ImageProvider.get("dialogs/conflict", "copybeforecurrentright"));
-            //putValue(NAME, tr("Add Selected"));
+            // putValue(NAME, tr("Add Selected"));
             refreshEnabled();
         }
 
         protected void refreshEnabled() {
-            setEnabled(selectionTableModel.getRowCount() >  0
+            setEnabled(selectionTableModel.getRowCount() > 0
                     && memberTableModel.getSelectionModel().getMinSelectionIndex() >= 0);
         }
 
         public void actionPerformed(ActionEvent e) {
-            memberTableModel.addMembersBeforeIdx(selectionTableModel.getSelection(), memberTableModel.getSelectionModel().getMinSelectionIndex());
+            memberTableModel.addMembersBeforeIdx(selectionTableModel.getSelection(), memberTableModel
+                    .getSelectionModel().getMinSelectionIndex());
         }
 
@@ -718,17 +711,19 @@
     class AddSelectedAfterSelection extends AbstractAction implements TableModelListener, ListSelectionListener {
         public AddSelectedAfterSelection() {
-            putValue(SHORT_DESCRIPTION,  tr("Add all primitives selected in the current dataset after the last selected member"));
+            putValue(SHORT_DESCRIPTION,
+                    tr("Add all primitives selected in the current dataset after the last selected member"));
             putValue(SMALL_ICON, ImageProvider.get("dialogs/conflict", "copyaftercurrentright"));
-            //putValue(NAME, tr("Add Selected"));
+            // putValue(NAME, tr("Add Selected"));
             refreshEnabled();
         }
 
         protected void refreshEnabled() {
-            setEnabled(selectionTableModel.getRowCount() >  0
+            setEnabled(selectionTableModel.getRowCount() > 0
                     && memberTableModel.getSelectionModel().getMinSelectionIndex() >= 0);
         }
 
         public void actionPerformed(ActionEvent e) {
-            memberTableModel.addMembersAfterIdx(selectionTableModel.getSelection(), memberTableModel.getSelectionModel().getMaxSelectionIndex());
+            memberTableModel.addMembersAfterIdx(selectionTableModel.getSelection(), memberTableModel
+                    .getSelectionModel().getMaxSelectionIndex());
         }
 
@@ -744,11 +739,9 @@
     class RemoveSelectedAction extends AbstractAction implements TableModelListener {
         public RemoveSelectedAction() {
-            putValue(SHORT_DESCRIPTION,  tr("Remove all currently selected objects from relation"));
+            putValue(SHORT_DESCRIPTION, tr("Remove all currently selected objects from relation"));
             putValue(SMALL_ICON, ImageProvider.get("dialogs", "removeselected"));
             // putValue(NAME, tr("Remove Selected"));
-            Shortcut.registerShortcut("relationeditor:removeselected",
-                    tr("Relation Editor: Remove Selected"),
-                    KeyEvent.VK_S,
-                    Shortcut.GROUP_MNEMONIC);
+            Shortcut.registerShortcut("relationeditor:removeselected", tr("Relation Editor: Remove Selected"),
+                    KeyEvent.VK_S, Shortcut.GROUP_MNEMONIC);
 
             DataSet ds = getLayer().data;
@@ -761,5 +754,20 @@
 
         public void tableChanged(TableModelEvent e) {
-            setEnabled(selectionTableModel.getRowCount() >0);
+            setEnabled(selectionTableModel.getRowCount() > 0);
+        }
+    }
+
+    class SortAction extends AbstractAction {
+        public SortAction() {
+            putValue(SHORT_DESCRIPTION, tr("Sort the relation members"));
+            putValue(SMALL_ICON, ImageProvider.get("dialogs", "sort"));
+            // putValue(NAME, tr("Sort"));
+            Shortcut.registerShortcut("relationeditor:sort", tr("Relation Editor: Sort"), KeyEvent.VK_T,
+                    Shortcut.GROUP_MNEMONIC);
+            setEnabled(false);
+        }
+
+        public void actionPerformed(ActionEvent e) {
+            memberTableModel.sort();
         }
     }
@@ -767,10 +775,8 @@
     class MoveUpAction extends AbstractAction implements ListSelectionListener {
         public MoveUpAction() {
-            putValue(SHORT_DESCRIPTION,  tr("Move the currently selected members up"));
+            putValue(SHORT_DESCRIPTION, tr("Move the currently selected members up"));
             putValue(SMALL_ICON, ImageProvider.get("dialogs", "moveup"));
-            //putValue(NAME, tr("Move Up"));
-            Shortcut.registerShortcut("relationeditor:moveup",
-                    tr("Relation Editor: Move Up"),
-                    KeyEvent.VK_N,
+            // putValue(NAME, tr("Move Up"));
+            Shortcut.registerShortcut("relationeditor:moveup", tr("Relation Editor: Move Up"), KeyEvent.VK_N,
                     Shortcut.GROUP_MNEMONIC);
             setEnabled(false);
@@ -788,10 +794,8 @@
     class MoveDownAction extends AbstractAction implements ListSelectionListener {
         public MoveDownAction() {
-            putValue(SHORT_DESCRIPTION,  tr("Move the currently selected members down"));
+            putValue(SHORT_DESCRIPTION, tr("Move the currently selected members down"));
             putValue(SMALL_ICON, ImageProvider.get("dialogs", "movedown"));
-            //putValue(NAME, tr("Move Down"));
-            Shortcut.registerShortcut("relationeditor:moveup",
-                    tr("Relation Editor: Move Down"),
-                    KeyEvent.VK_J,
+            // putValue(NAME, tr("Move Down"));
+            Shortcut.registerShortcut("relationeditor:moveup", tr("Relation Editor: Move Down"), KeyEvent.VK_J,
                     Shortcut.GROUP_MNEMONIC);
             setEnabled(false);
@@ -809,10 +813,8 @@
     class RemoveAction extends AbstractAction implements ListSelectionListener {
         public RemoveAction() {
-            putValue(SHORT_DESCRIPTION,  tr("Remove the member in the current table row from this relation"));
+            putValue(SHORT_DESCRIPTION, tr("Remove the member in the current table row from this relation"));
             putValue(SMALL_ICON, ImageProvider.get("dialogs", "remove"));
-            //putValue(NAME, tr("Remove"));
-            Shortcut.registerShortcut("relationeditor:remove",
-                    tr("Relation Editor: Remove"),
-                    KeyEvent.VK_J,
+            // putValue(NAME, tr("Remove"));
+            Shortcut.registerShortcut("relationeditor:remove", tr("Relation Editor: Remove"), KeyEvent.VK_J,
                     Shortcut.GROUP_MNEMONIC);
             setEnabled(false);
@@ -830,5 +832,5 @@
     class OKAction extends AbstractAction {
         public OKAction() {
-            putValue(SHORT_DESCRIPTION,  tr("Apply the updates and close the dialog"));
+            putValue(SHORT_DESCRIPTION, tr("Apply the updates and close the dialog"));
             putValue(SMALL_ICON, ImageProvider.get("ok"));
             putValue(NAME, tr("Apply"));
@@ -844,5 +846,5 @@
     class CancelAction extends AbstractAction {
         public CancelAction() {
-            putValue(SHORT_DESCRIPTION,  tr("Cancel the updates and close the dialog"));
+            putValue(SHORT_DESCRIPTION, tr("Cancel the updates and close the dialog"));
             putValue(SMALL_ICON, ImageProvider.get("cancel"));
             putValue(NAME, tr("Cancel"));
@@ -861,9 +863,10 @@
     class AddTagAction extends AbstractAction {
         public AddTagAction() {
-            putValue(SHORT_DESCRIPTION,  tr("Add an empty tag"));
-            putValue(SMALL_ICON, ImageProvider.get("dialogs","add"));
-            //putValue(NAME, tr("Cancel"));
+            putValue(SHORT_DESCRIPTION, tr("Add an empty tag"));
+            putValue(SMALL_ICON, ImageProvider.get("dialogs", "add"));
+            // putValue(NAME, tr("Cancel"));
             setEnabled(true);
         }
+
         public void actionPerformed(ActionEvent e) {
             tagEditorModel.appendNewTag();
@@ -871,9 +874,9 @@
     }
 
-    class DeleteTagAction extends AbstractAction implements ListSelectionListener{
+    class DeleteTagAction extends AbstractAction implements ListSelectionListener {
         public DeleteTagAction() {
-            putValue(SHORT_DESCRIPTION,  tr("Delete the currently selected tags"));
-            putValue(SMALL_ICON, ImageProvider.get("dialogs","delete"));
-            //putValue(NAME, tr("Cancel"));
+            putValue(SHORT_DESCRIPTION, tr("Delete the currently selected tags"));
+            putValue(SMALL_ICON, ImageProvider.get("dialogs", "delete"));
+            // putValue(NAME, tr("Cancel"));
             refreshEnabled();
         }
@@ -917,5 +920,6 @@
                     // should not happen
                     //
-                    throw new IllegalStateException("unexpected selected clolumn: getSelectedColumn() is " + tagTable.getSelectedColumn());
+                    throw new IllegalStateException("unexpected selected clolumn: getSelectedColumn() is "
+                            + tagTable.getSelectedColumn());
             } else if (tagTable.getSelectedColumnCount() == 2) {
                 deleteTags();
@@ -927,5 +931,5 @@
 
         protected void refreshEnabled() {
-            setEnabled(tagTable.getSelectedRowCount()>0 || tagTable.getSelectedColumnCount() > 0);
+            setEnabled(tagTable.getSelectedRowCount() > 0 || tagTable.getSelectedColumnCount() > 0);
         }
 
@@ -937,13 +941,12 @@
     class DownlaodAction extends AbstractAction {
         public DownlaodAction() {
-            putValue(SHORT_DESCRIPTION,   tr("Download all incomplete ways and nodes in relation"));
-            putValue(SMALL_ICON, ImageProvider.get("dialogs","downloadincomplete"));
+            putValue(SHORT_DESCRIPTION, tr("Download all incomplete ways and nodes in relation"));
+            putValue(SMALL_ICON, ImageProvider.get("dialogs", "downloadincomplete"));
             putValue(NAME, tr("Download Members"));
-            Shortcut.registerShortcut("relationeditor:downloadincomplete",
-                    tr("Relation Editor: Download Members"),
-                    KeyEvent.VK_K,
-                    Shortcut.GROUP_MNEMONIC);
+            Shortcut.registerShortcut("relationeditor:downloadincomplete", tr("Relation Editor: Download Members"),
+                    KeyEvent.VK_K, Shortcut.GROUP_MNEMONIC);
             setEnabled(true);
         }
+
         public void actionPerformed(ActionEvent e) {
             downloadRelationMembers();
@@ -951,7 +954,7 @@
     }
 
-    class SetRoleAction extends AbstractAction implements ListSelectionListener, DocumentListener{
+    class SetRoleAction extends AbstractAction implements ListSelectionListener, DocumentListener {
         public SetRoleAction() {
-            putValue(SHORT_DESCRIPTION,   tr("Sets a role for the selected members"));
+            putValue(SHORT_DESCRIPTION, tr("Sets a role for the selected members"));
             // FIXME: find better icon
             putValue(SMALL_ICON, ImageProvider.get("ok"));
@@ -987,9 +990,9 @@
     /**
      * Creates a new relation with a copy of the current editor state
-     *
+     * 
      */
     class DuplicateRelationAction extends AbstractAction {
         public DuplicateRelationAction() {
-            putValue(SHORT_DESCRIPTION,   tr("Create a copy of this relation and open it in another editor window"));
+            putValue(SHORT_DESCRIPTION, tr("Create a copy of this relation and open it in another editor window"));
             // FIXME provide an icon
             putValue(SMALL_ICON, ImageProvider.get("duplicate"));
@@ -997,4 +1000,5 @@
             setEnabled(true);
         }
+
         public void actionPerformed(ActionEvent e) {
             Relation copy = new Relation();
@@ -1010,6 +1014,6 @@
     /**
      * Action for editing the currently selected relation
-     *
-     *
+     * 
+     * 
      */
     class EditAction extends AbstractAction implements ListSelectionListener {
@@ -1022,14 +1026,18 @@
 
         protected void refreshEnabled() {
-            setEnabled(memberTable.getSelectedRowCount() == 1 && memberTableModel.isEditableRelation(memberTable.getSelectedRow()));
-        }
-
-        public void run()  {
+            setEnabled(memberTable.getSelectedRowCount() == 1
+                    && memberTableModel.isEditableRelation(memberTable.getSelectedRow()));
+        }
+
+        public void run() {
             int idx = memberTable.getSelectedRow();
-            if (idx < 0) return;
+            if (idx < 0)
+                return;
             OsmPrimitive primitive = memberTableModel.getReferredPrimitive(idx);
-            if (! (primitive instanceof Relation)) return;
-            Relation r= (Relation)primitive;
-            if (r.incomplete) return;
+            if (!(primitive instanceof Relation))
+                return;
+            Relation r = (Relation) primitive;
+            if (r.incomplete)
+                return;
             RelationEditor editor = RelationEditor.getEditor(getLayer(), r, null);
             editor.setVisible(true);
@@ -1060,5 +1068,6 @@
             ArrayList<OsmPrimitive> sel;
             int cnt = memberTable.getSelectedRowCount();
-            if (cnt <=0) return;
+            if (cnt <= 0)
+                return;
             sel = new ArrayList<OsmPrimitive>(cnt);
             for (int i : memberTable.getSelectedRows()) {
@@ -1071,6 +1080,6 @@
     /**
      * The asynchronous task for downloading relation members.
-     *
-     *
+     * 
+     * 
      */
     class DownloadTask extends PleaseWaitRunnable {
@@ -1080,6 +1089,11 @@
 
         public DownloadTask(Dialog parent) {
-            super(tr("Download relation members"), new PleaseWaitProgressMonitor(parent), false /* don't ignore exception */);
-        }
+            super(tr("Download relation members"), new PleaseWaitProgressMonitor(parent), false /*
+             * don't
+             * ignore
+             * exception
+             */);
+        }
+
         @Override
         protected void cancel() {
@@ -1093,15 +1107,11 @@
                 msg = lastException.toString();
             }
-            JOptionPane.showMessageDialog(
-                    null,
-                    msg,
-                    tr("Error"),
-                    JOptionPane.ERROR_MESSAGE
-            );
+            JOptionPane.showMessageDialog(null, msg, tr("Error"), JOptionPane.ERROR_MESSAGE);
         }
 
         @Override
         protected void finish() {
-            if (cancelled) return;
+            if (cancelled)
+                return;
             memberTableModel.updateMemberReferences(getLayer().data);
             if (lastException != null) {
@@ -1110,9 +1120,6 @@
 
             if (conflictsCount > 0) {
-                JOptionPane op = new JOptionPane(
-                        tr("There were {0} conflicts during import.",
-                                conflictsCount),
-                                JOptionPane.WARNING_MESSAGE
-                );
+                JOptionPane op = new JOptionPane(tr("There were {0} conflicts during import.", conflictsCount),
+                        JOptionPane.WARNING_MESSAGE);
                 JDialog dialog = op.createDialog(GenericRelationEditor.this, tr("Conflicts in data"));
                 dialog.setAlwaysOnTop(true);
@@ -1127,6 +1134,8 @@
             try {
                 progressMonitor.indeterminateSubTask("");
-                OsmServerObjectReader reader = new OsmServerObjectReader(getRelation().id, OsmPrimitiveType.RELATION, true);
-                DataSet dataSet = reader.parseOsm(progressMonitor.createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
+                OsmServerObjectReader reader = new OsmServerObjectReader(getRelation().id, OsmPrimitiveType.RELATION,
+                        true);
+                DataSet dataSet = reader.parseOsm(progressMonitor
+                        .createSubTaskMonitor(ProgressMonitor.ALL_TICKS, false));
                 if (dataSet != null) {
                     final MergeVisitor visitor = new MergeVisitor(getLayer().data, dataSet);
@@ -1137,15 +1146,13 @@
                         getLayer().data.dataSources.add(src);
                     }
-                    // FIXME: this is necessary because there are  dialogs listening
+                    // FIXME: this is necessary because there are dialogs listening
                     // for DataChangeEvents which manipulate Swing components on this
                     // thread.
                     //
-                    SwingUtilities.invokeLater(
-                            new Runnable() {
-                                public void run() {
-                                    getLayer().fireDataChange();
-                                }
-                            }
-                    );
+                    SwingUtilities.invokeLater(new Runnable() {
+                        public void run() {
+                            getLayer().fireDataChange();
+                        }
+                    });
                     if (!visitor.getConflicts().isEmpty()) {
                         getLayer().getConflicts().add(visitor.getConflicts());
@@ -1153,7 +1160,8 @@
                     }
                 }
-            } catch(Exception e) {
+            } catch (Exception e) {
                 if (cancelled) {
-                    System.out.println(tr("Warning: ignoring exception because task is cancelled. Exception: {0}", e.toString()));
+                    System.out.println(tr("Warning: ignoring exception because task is cancelled. Exception: {0}", e
+                            .toString()));
                     return;
                 }
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableCellRenderer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableCellRenderer.java	(revision 1821)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableCellRenderer.java	(revision 1822)
@@ -6,7 +6,5 @@
 import java.util.ArrayList;
 import java.util.Collections;
-import java.util.HashMap;
 
-import javax.swing.ImageIcon;
 import javax.swing.JLabel;
 import javax.swing.JTable;
@@ -14,7 +12,4 @@
 
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
-import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
-import org.openstreetmap.josm.gui.PrimitiveNameFormatter;
-import org.openstreetmap.josm.tools.ImageProvider;
 
 /**
@@ -22,27 +17,10 @@
  * 
  */
-public  class MemberTableCellRenderer extends JLabel implements TableCellRenderer {
-    static private final PrimitiveNameFormatter NAME_FORMATTER = new PrimitiveNameFormatter();
+public abstract class MemberTableCellRenderer extends JLabel implements TableCellRenderer {
+    public final static Color BGCOLOR_SELECTED = new Color(143, 170, 255);
+    public final static Color BGCOLOR_EMPTY_ROW = new Color(234, 234, 234);
 
-    public final static Color BGCOLOR_SELECTED = new Color(143,170,255);
-    public final static Color BGCOLOR_EMPTY_ROW = new Color(234,234,234);
-
-    public final static Color BGCOLOR_NOT_IN_OPPOSITE = new Color(255,197,197);
-    public final static Color BGCOLOR_DOUBLE_ENTRY = new Color(255,234,213);
-
-
-    private HashMap<OsmPrimitiveType, ImageIcon>  icons;
-
-    /**
-     * Load the image icon for an OSM primitive of type node
-     * 
-     * @return the icon; null, if not found
-     */
-    protected void loadIcons() {
-        icons = new HashMap<OsmPrimitiveType, ImageIcon>();
-        icons.put(OsmPrimitiveType.NODE,ImageProvider.get("data", "node"));
-        icons.put(OsmPrimitiveType.WAY, ImageProvider.get("data", "way"));
-        icons.put(OsmPrimitiveType.RELATION, ImageProvider.get("data", "relation"));
-    }
+    public final static Color BGCOLOR_NOT_IN_OPPOSITE = new Color(255, 197, 197);
+    public final static Color BGCOLOR_DOUBLE_ENTRY = new Color(255, 234, 213);
 
     /**
@@ -52,5 +30,4 @@
         setIcon(null);
         setOpaque(true);
-        loadIcons();
     }
 
@@ -58,7 +35,5 @@
         StringBuilder sb = new StringBuilder();
         sb.append("<html>");
-        sb.append("<strong>id</strong>=")
-        .append(primitive.id)
-        .append("<br>");
+        sb.append("<strong>id</strong>=").append(primitive.id).append("<br>");
         ArrayList<String> keyList = new ArrayList<String>(primitive.keySet());
         Collections.sort(keyList);
@@ -68,11 +43,8 @@
             }
             String key = keyList.get(i);
-            sb.append("<strong>")
-            .append(key)
-            .append("</strong>")
-            .append("=");
+            sb.append("<strong>").append(key).append("</strong>").append("=");
             String value = primitive.get(key);
-            while(value.length() != 0) {
-                sb.append(value.substring(0,Math.min(50, value.length())));
+            while (value.length() != 0) {
+                sb.append(value.substring(0, Math.min(50, value.length())));
                 if (value.length() > 50) {
                     sb.append("<br>");
@@ -98,5 +70,5 @@
     }
 
-    protected void renderBackground( MemberTableModel model, OsmPrimitive primitive, boolean isSelected) {
+    protected void renderBackground(MemberTableModel model, OsmPrimitive primitive, boolean isSelected) {
         Color bgc = Color.WHITE;
         if (isSelected) {
@@ -113,44 +85,14 @@
     }
 
-    protected void renderPrimitive(OsmPrimitive primitive) {
-        setIcon(icons.get(OsmPrimitiveType.from(primitive)));
-        setText(NAME_FORMATTER.getName(primitive));
-        setToolTipText(buildToolTipText(primitive));
-    }
-
-    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
-            int row, int column) {
-
-        reset();
-
-        renderForeground(isSelected);
-        switch(column) {
-        case 0:
-            String role = (String)value;
-            renderBackground(getModel(table), null, isSelected);
-            setText(role);
-            break;
-        case 1:
-            OsmPrimitive primitive = (OsmPrimitive)value;
-            renderBackground(getModel(table), primitive, isSelected);
-            renderPrimitive(primitive);
-            break;
-        case 2:
-            setText("");
-            renderBackground(getModel(table), null, isSelected);
-            break;
-        default:
-            // should not happen
-        }
-        return this;
-    }
+    abstract public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
+            boolean hasFocus, int row, int column);
 
     /**
      * replies the model
-     * @param table  the table
+     * @param table the table
      * @return the table model
      */
     protected MemberTableModel getModel(JTable table) {
-        return (MemberTableModel)table.getModel();
+        return (MemberTableModel) table.getModel();
     }
 }
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableColumnModel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableColumnModel.java	(revision 1821)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableColumnModel.java	(revision 1822)
@@ -7,11 +7,8 @@
 import javax.swing.table.TableColumn;
 
-import org.openstreetmap.josm.gui.OsmPrimitivRenderer;
-
-public class MemberTableColumnModel extends DefaultTableColumnModel{
+public class MemberTableColumnModel extends DefaultTableColumnModel {
 
     public MemberTableColumnModel() {
         TableColumn col = null;
-        MemberTableCellRenderer renderer = new MemberTableCellRenderer();
 
         // column 0 - the member role
@@ -19,5 +16,5 @@
         col.setHeaderValue(tr("Role"));
         col.setResizable(true);
-        col.setCellRenderer(renderer);
+        col.setCellRenderer(new MemberTableRoleCellRenderer());
 
         addColumn(col);
@@ -27,6 +24,6 @@
         col.setHeaderValue(tr("Refers to"));
         col.setResizable(true);
-        col.setCellRenderer(new OsmPrimitivRenderer());
-        col.setCellRenderer(renderer);
+        // col.setCellRenderer(new OsmPrimitivRenderer());
+        col.setCellRenderer(new MemberTableMemberCellRenderer());
         addColumn(col);
 
@@ -35,5 +32,5 @@
         col.setHeaderValue(tr("Linked"));
         col.setResizable(true);
-        col.setCellRenderer(renderer);
+        col.setCellRenderer(new MemberTableLinkedCellRenderer());
         addColumn(col);
     }
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableLinkedCellRenderer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableLinkedCellRenderer.java	(revision 1822)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableLinkedCellRenderer.java	(revision 1822)
@@ -0,0 +1,20 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.dialogs.relation;
+
+import java.awt.Component;
+
+import javax.swing.JTable;
+
+public class MemberTableLinkedCellRenderer extends MemberTableCellRenderer {
+
+    @Override
+    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
+            int row, int column) {
+        reset();
+
+        renderForeground(isSelected);
+        setText(value.toString());
+        renderBackground(getModel(table), null, isSelected);
+        return this;
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableMemberCellRenderer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableMemberCellRenderer.java	(revision 1822)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableMemberCellRenderer.java	(revision 1822)
@@ -0,0 +1,54 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.dialogs.relation;
+
+import java.awt.Component;
+import java.util.HashMap;
+
+import javax.swing.ImageIcon;
+import javax.swing.JTable;
+
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.data.osm.OsmPrimitiveType;
+import org.openstreetmap.josm.gui.PrimitiveNameFormatter;
+import org.openstreetmap.josm.tools.ImageProvider;
+
+public class MemberTableMemberCellRenderer extends MemberTableCellRenderer {
+    private HashMap<OsmPrimitiveType, ImageIcon> icons;
+    static private final PrimitiveNameFormatter NAME_FORMATTER = new PrimitiveNameFormatter();
+
+    public MemberTableMemberCellRenderer() {
+        super();
+        loadIcons();
+    }
+
+    /**
+     * Load the image icon for an OSM primitive of type node
+     * 
+     * @return the icon; null, if not found
+     */
+    protected void loadIcons() {
+        icons = new HashMap<OsmPrimitiveType, ImageIcon>();
+        icons.put(OsmPrimitiveType.NODE, ImageProvider.get("data", "node"));
+        icons.put(OsmPrimitiveType.WAY, ImageProvider.get("data", "way"));
+        icons.put(OsmPrimitiveType.RELATION, ImageProvider.get("data", "relation"));
+    }
+
+    protected void renderPrimitive(OsmPrimitive primitive) {
+        setIcon(icons.get(OsmPrimitiveType.from(primitive)));
+        setText(NAME_FORMATTER.getName(primitive));
+        setToolTipText(buildToolTipText(primitive));
+    }
+
+    @Override
+    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
+            int row, int column) {
+
+        reset();
+
+        renderForeground(isSelected);
+        OsmPrimitive primitive = (OsmPrimitive) value;
+        renderBackground(getModel(table), primitive, isSelected);
+        renderPrimitive(primitive);
+        return this;
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableModel.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableModel.java	(revision 1821)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableModel.java	(revision 1822)
@@ -7,5 +7,7 @@
 import java.util.Collections;
 import java.util.Iterator;
+import java.util.LinkedList;
 import java.util.List;
+import java.util.Vector;
 import java.util.concurrent.CopyOnWriteArrayList;
 
@@ -15,13 +17,13 @@
 
 import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.Node;
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.data.osm.Relation;
 import org.openstreetmap.josm.data.osm.RelationMember;
-
-public class MemberTableModel extends AbstractTableModel{
-
-    private Relation relation;
+import org.openstreetmap.josm.data.osm.Way;
+
+public class MemberTableModel extends AbstractTableModel {
+
     private ArrayList<RelationMember> members;
-    private ArrayList<String> memberLinkingInfo;
     private DefaultListSelectionModel listSelectionModel;
     private CopyOnWriteArrayList<IMemberModelListener> listeners;
@@ -30,13 +32,12 @@
      * constructor
      */
-    public MemberTableModel(){
+    public MemberTableModel() {
         members = new ArrayList<RelationMember>();
-        memberLinkingInfo = new ArrayList<String>();
         listeners = new CopyOnWriteArrayList<IMemberModelListener>();
     }
 
     public void addMemberModelListener(IMemberModelListener listener) {
-        synchronized(listeners) {
-            if (listener != null && ! listeners.contains(listener)) {
+        synchronized (listeners) {
+            if (listener != null && !listeners.contains(listener)) {
                 listeners.add(listener);
             }
@@ -45,5 +46,5 @@
 
     public void removeMemberModelListener(IMemberModelListener listener) {
-        synchronized(listeners) {
+        synchronized (listeners) {
             if (listener != null && listeners.contains(listener)) {
                 listeners.remove(listener);
@@ -53,6 +54,6 @@
 
     protected void fireMakeMemberVisible(int index) {
-        synchronized(listeners) {
-            for (IMemberModelListener listener: listeners) {
+        synchronized (listeners) {
+            for (IMemberModelListener listener : listeners) {
                 listener.makeMemberVisible(index);
             }
@@ -65,5 +66,4 @@
             members.addAll(relation.members);
         }
-        this.relation = relation;
         fireTableDataChanged();
     }
@@ -78,8 +78,11 @@
 
     public Object getValueAt(int rowIndex, int columnIndex) {
-        switch(columnIndex) {
-        case 0: return members.get(rowIndex).role;
-        case 1: return members.get(rowIndex).member;
-        case 2: return "";
+        switch (columnIndex) {
+        case 0:
+            return members.get(rowIndex).role;
+        case 1:
+            return members.get(rowIndex).member;
+        case 2:
+            return linked(rowIndex);
         }
         // should not happen
@@ -98,5 +101,4 @@
     }
 
-
     public OsmPrimitive getReferredPrimitive(int idx) {
         return members.get(idx).member;
@@ -104,12 +106,12 @@
 
     public void moveUp(int[] selectedRows) {
-        if (! canMoveUp(selectedRows))
+        if (!canMoveUp(selectedRows))
             return;
 
         for (int row : selectedRows) {
             RelationMember member1 = members.get(row);
-            RelationMember member2 = members.get(row-1);
+            RelationMember member2 = members.get(row - 1);
             members.set(row, member2);
-            members.set(row-1, member1);
+            members.set(row - 1, member1);
         }
         fireTableDataChanged();
@@ -120,17 +122,17 @@
             listSelectionModel.addSelectionInterval(row, row);
         }
-        fireMakeMemberVisible(selectedRows[0] -1);
+        fireMakeMemberVisible(selectedRows[0] - 1);
     }
 
     public void moveDown(int[] selectedRows) {
-        if (! canMoveDown(selectedRows))
-            return;
-
-        for (int i=selectedRows.length-1; i >=0; i--) {
+        if (!canMoveDown(selectedRows))
+            return;
+
+        for (int i = selectedRows.length - 1; i >= 0; i--) {
             int row = selectedRows[i];
             RelationMember member1 = members.get(row);
-            RelationMember member2 = members.get(row+1);
+            RelationMember member2 = members.get(row + 1);
             members.set(row, member2);
-            members.set(row+1, member1);
+            members.set(row + 1, member1);
         }
         fireTableDataChanged();
@@ -145,5 +147,5 @@
 
     public void remove(int[] selectedRows) {
-        if (! canRemove(selectedRows))
+        if (!canRemove(selectedRows))
             return;
         int offset = 0;
@@ -156,18 +158,21 @@
     }
 
-    public boolean canMoveUp(int [] rows) {
-        if (rows == null || rows.length == 0) return false;
+    public boolean canMoveUp(int[] rows) {
+        if (rows == null || rows.length == 0)
+            return false;
         Arrays.sort(rows);
         return rows[0] > 0 && members.size() > 0;
     }
 
-    public boolean canMoveDown(int [] rows) {
-        if (rows == null || rows.length == 0) return false;
+    public boolean canMoveDown(int[] rows) {
+        if (rows == null || rows.length == 0)
+            return false;
         Arrays.sort(rows);
-        return members.size() >0 && rows[rows.length-1] < members.size() - 1;
-    }
-
-    public boolean canRemove(int [] rows) {
-        if (rows == null || rows.length == 0) return false;
+        return members.size() > 0 && rows[rows.length - 1] < members.size() - 1;
+    }
+
+    public boolean canRemove(int[] rows) {
+        if (rows == null || rows.length == 0)
+            return false;
         return true;
     }
@@ -195,7 +200,8 @@
 
     public void removeMembersReferringTo(List<? extends OsmPrimitive> primitives) {
-        if (primitives == null) return;
+        if (primitives == null)
+            return;
         Iterator<RelationMember> it = members.iterator();
-        while(it.hasNext()) {
+        while (it.hasNext()) {
             RelationMember member = it.next();
             if (primitives.contains(member.member)) {
@@ -212,8 +218,10 @@
 
     public boolean hasSameMembersAs(Relation relation) {
-        if (relation == null) return false;
-        if (relation.members.size() != members.size()) return false;
-        for (int i=0; i<relation.members.size();i++) {
-            if (! relation.members.get(i).equals(members.get(i)))
+        if (relation == null)
+            return false;
+        if (relation.members.size() != members.size())
+            return false;
+        for (int i = 0; i < relation.members.size(); i++) {
+            if (!relation.members.get(i).equals(members.get(i)))
                 return false;
         }
@@ -222,5 +230,5 @@
 
     public boolean hasIncompleteMembers() {
-        for (RelationMember member: members) {
+        for (RelationMember member : members) {
             if (member.member.incomplete)
                 return true;
@@ -231,5 +239,5 @@
     protected List<Integer> getSelectedIndices() {
         ArrayList<Integer> selectedIndices = new ArrayList<Integer>();
-        for (int i=0; i< members.size();i++) {
+        for (int i = 0; i < members.size(); i++) {
             if (getSelectionModel().isSelectedIndex(i)) {
                 selectedIndices.add(i);
@@ -240,13 +248,14 @@
 
     public void addMembersAtBeginning(List<? extends OsmPrimitive> primitives) {
-        if (primitives == null) return;
-        for (OsmPrimitive primitive: primitives) {
-            RelationMember member = new RelationMember(null,primitive);
-            members.add(0,member);
+        if (primitives == null)
+            return;
+        for (OsmPrimitive primitive : primitives) {
+            RelationMember member = new RelationMember(null, primitive);
+            members.add(0, member);
         }
         fireTableDataChanged();
         getSelectionModel().clearSelection();
-        for (int i=0; i<primitives.size();i++) {
-            getSelectionModel().addSelectionInterval(i,i);
+        for (int i = 0; i < primitives.size(); i++) {
+            getSelectionModel().addSelectionInterval(i, i);
         }
         fireMakeMemberVisible(0);
@@ -254,29 +263,31 @@
 
     public void addMembersAtEnd(List<? extends OsmPrimitive> primitives) {
-        if (primitives == null) return;
-
-        for (OsmPrimitive primitive: primitives) {
-            RelationMember member = new RelationMember(null,primitive);
+        if (primitives == null)
+            return;
+
+        for (OsmPrimitive primitive : primitives) {
+            RelationMember member = new RelationMember(null, primitive);
             members.add(member);
         }
         fireTableDataChanged();
         getSelectionModel().clearSelection();
-        for (int i=0; i<primitives.size();i++) {
-            getSelectionModel().addSelectionInterval(members.size()-1-i,members.size()-1-i);
-        }
-        fireMakeMemberVisible(members.size() -1);
+        for (int i = 0; i < primitives.size(); i++) {
+            getSelectionModel().addSelectionInterval(members.size() - 1 - i, members.size() - 1 - i);
+        }
+        fireMakeMemberVisible(members.size() - 1);
     }
 
     public void addMembersBeforeIdx(List<? extends OsmPrimitive> primitives, int idx) {
-        if (primitives == null) return;
-
-        for (OsmPrimitive primitive: primitives) {
-            RelationMember member = new RelationMember(null,primitive);
-            members.add(idx,member);
+        if (primitives == null)
+            return;
+
+        for (OsmPrimitive primitive : primitives) {
+            RelationMember member = new RelationMember(null, primitive);
+            members.add(idx, member);
         }
         fireTableDataChanged();
         getSelectionModel().clearSelection();
-        for (int i=0; i<primitives.size();i++) {
-            getSelectionModel().addSelectionInterval(idx+i,idx+i);
+        for (int i = 0; i < primitives.size(); i++) {
+            getSelectionModel().addSelectionInterval(idx + i, idx + i);
         }
         fireMakeMemberVisible(idx);
@@ -284,17 +295,18 @@
 
     public void addMembersAfterIdx(List<? extends OsmPrimitive> primitives, int idx) {
-        if (primitives == null) return;
-        int j =1;
-        for (OsmPrimitive primitive: primitives) {
-            RelationMember member = new RelationMember(null,primitive);
-            members.add(idx+j,member);
+        if (primitives == null)
+            return;
+        int j = 1;
+        for (OsmPrimitive primitive : primitives) {
+            RelationMember member = new RelationMember(null, primitive);
+            members.add(idx + j, member);
             j++;
         }
         fireTableDataChanged();
         getSelectionModel().clearSelection();
-        for (int i=0; i<primitives.size();i++) {
-            getSelectionModel().addSelectionInterval(idx+1 + i,idx+1 +i);
-        }
-        fireMakeMemberVisible(idx+1);
+        for (int i = 0; i < primitives.size(); i++) {
+            getSelectionModel().addSelectionInterval(idx + 1 + i, idx + 1 + i);
+        }
+        fireMakeMemberVisible(idx + 1);
     }
 
@@ -306,5 +318,5 @@
      */
     public int getNumMembersWithPrimitive(OsmPrimitive primitive) {
-        int count  = 0;
+        int count = 0;
         for (RelationMember member : members) {
             if (member.member.equals(primitive)) {
@@ -321,11 +333,12 @@
      * @param role the new role
      */
-    public void updateRole(int [] idx, String role) {
-        if (idx == null || idx.length == 0) return;
-        for (int row: idx) {
+    public void updateRole(int[] idx, String role) {
+        if (idx == null || idx.length == 0)
+            return;
+        for (int row : idx) {
             members.get(row).role = role;
         }
         fireTableDataChanged();
-        for (int row: idx) {
+        for (int row : idx) {
             getSelectionModel().addSelectionInterval(row, row);
         }
@@ -333,5 +346,5 @@
 
     /**
-     * Replies a collection with the currently selected relation members
+     * Get the currently selected relation members
      * 
      * @return a collection with the currently selected relation members
@@ -339,5 +352,5 @@
     public Collection<RelationMember> getSelectedMembers() {
         ArrayList<RelationMember> selectedMembers = new ArrayList<RelationMember>();
-        for (int i: getSelectedIndices()) {
+        for (int i : getSelectedIndices()) {
             selectedMembers.add(members.get(i));
         }
@@ -345,7 +358,6 @@
     }
 
-
     /**
-     * Selectes the members in the collection selectedMembers
+     * Selects the members in the collection selectedMembers
      * 
      * @param selectedMembers the collection of selected members
@@ -358,5 +370,5 @@
         //
         ArrayList<Integer> selectedIndices = new ArrayList<Integer>();
-        for (RelationMember member: selectedMembers) {
+        for (RelationMember member : selectedMembers) {
             int idx = members.indexOf(member);
             if (idx >= 0 && !selectedIndices.contains(idx)) {
@@ -381,9 +393,194 @@
 
     public boolean isEditableRelation(int row) {
-        if (row < 0 || row >= members.size()) return false;
+        if (row < 0 || row >= members.size())
+            return false;
         RelationMember member = members.get(row);
-        if (!(member.member instanceof Relation)) return false;
-        Relation r = (Relation)member.member;
-        return ! r.incomplete;
+        if (!(member.member instanceof Relation))
+            return false;
+        Relation r = (Relation) member.member;
+        return !r.incomplete;
+    }
+
+    void sort() {
+        RelationNodeMap map = new RelationNodeMap(members);
+        Vector<LinkedList<Integer>> segments;
+        LinkedList<Integer> segment;
+        Node startSearchNode;
+        Node endSearchNode;
+        boolean something_done;
+
+        /*
+         * sort any 2 or more connected elements together may be slow with many unconnected members
+         * TODO: cleanup again, too much code in 1 method
+         */
+
+        if (map.isEmpty())
+            // empty relation or incomplete members
+            return;
+        segments = new Vector<LinkedList<Integer>>();
+        // add first member of relation, not strictly necessary
+        if (map.remove(0, members.get(0))) {
+            segment = new LinkedList<Integer>();
+            segment.add(Integer.valueOf(0));
+            segments.add(segment);
+        }
+        while (!map.isEmpty()) {
+            segment = segments.lastElement();
+
+            do {
+                something_done = false;
+                startSearchNode = null;
+                endSearchNode = null;
+                if (segment.size() == 1) {
+                    RelationMember m = members.get(segment.getFirst());
+                    if (m.member instanceof Way) {
+                        Way w = (Way) m.member;
+                        endSearchNode = w.lastNode();
+                        startSearchNode = w.firstNode();
+                    } else if (m.member instanceof Node) {
+                        Node n = (Node) m.member;
+                        endSearchNode = n;
+                    }
+                } else {
+                    // add unused node of first element and unused node of last element
+                    // start with the first element
+                    RelationMember element = members.get(segment.getFirst());
+                    RelationMember other_element = members.get(segment.get(1));
+
+                    if (element.member instanceof Way) {
+                        Way w = (Way) element.member;
+                        if (other_element.member instanceof Way) {
+                            Way x = (Way) other_element.member;
+                            if ((w.firstNode() == x.firstNode()) || (w.firstNode() == x.lastNode())) {
+                                startSearchNode = w.lastNode();
+                            } else {
+                                startSearchNode = w.firstNode();
+                            }
+                        } else if (other_element.member instanceof Node) {
+                            Node m = (Node) other_element.member;
+                            if (w.firstNode() == m) {
+                                startSearchNode = w.lastNode();
+                            } else {
+                                startSearchNode = w.firstNode();
+                            }
+                        }
+                    } else if (element.member instanceof Node) {
+                        Node n = (Node) element.member;
+                        startSearchNode = n;
+                    }
+
+                    // now the same for the last element
+                    element = members.get(segment.getLast());
+                    other_element = members.get(segment.get(segment.size() - 2));
+
+                    if (element.member instanceof Way) {
+                        Way w = (Way) element.member;
+                        if (other_element.member instanceof Way) {
+                            Way x = (Way) other_element.member;
+                            if ((w.firstNode() == x.firstNode()) || (w.firstNode() == x.lastNode())) {
+                                endSearchNode = w.lastNode();
+                            } else {
+                                endSearchNode = w.firstNode();
+                            }
+                        } else if (other_element.member instanceof Node) {
+                            Node m = (Node) other_element.member;
+                            if (w.firstNode() == m) {
+                                endSearchNode = w.lastNode();
+                            } else {
+                                endSearchNode = w.firstNode();
+                            }
+                        }
+                    } else if (element.member instanceof Node) {
+                        Node n = (Node) element.member;
+                        endSearchNode = n;
+                    }
+                }
+
+                // let's see if we can find connected elements for endSearchNode and startSearchNode
+                if (startSearchNode != null) {
+                    Integer m2 = map.find(startSearchNode, segment.getFirst());
+                    if (m2 != null) {
+                        segment.add(0, m2);
+                        map.remove(m2, members.get(m2));
+                        something_done = true;
+                    }
+                }
+                if (endSearchNode != null) {
+                    Integer m2 = map.find(endSearchNode, segment.getLast());
+                    if (m2 != null) {
+                        segment.add(segment.size(), m2);
+                        map.remove(m2, members.get(m2));
+                        something_done = true;
+                    }
+                }
+            } while (something_done);
+
+            Integer next = map.pop();
+            if (next == null) {
+                break;
+            }
+
+            segment = new LinkedList<Integer>();
+            segment.add(next);
+            segments.add(segment);
+        }
+        // append map.remaining() to segments list (as a single segment)
+        segment = new LinkedList<Integer>();
+        segment.addAll(map.getRemaining());
+        segments.add(segment);
+
+        // now we need to actually re-order the relation members
+        ArrayList<RelationMember> newmembers = new ArrayList<RelationMember>();
+        for (LinkedList<Integer> segment2 : segments) {
+            for (Integer p : segment2) {
+                newmembers.add(members.get(p));
+            }
+        }
+        members.clear();
+        members.addAll(newmembers);
+
+        fireTableDataChanged();
+    }
+
+    // simple version of code that was removed from GenericReleationEditor
+    // no recursion and no forward/backward support
+    // TODO: add back the number of linked elements
+    private WayConnectionType linked(int i) {
+        // this method is aimed at finding out whether the
+        // relation member is "linked" with the next, i.e. whether
+        // (if both are ways) these ways are connected. It should
+        // really produce a much more beautiful output (with a linkage
+        // symbol somehow placed between the two member lines!),
+        // so... FIXME ;-)
+
+        WayConnectionType link = WayConnectionType.none;
+        RelationMember m1 = members.get(i);
+        RelationMember m2 = members.get((i + 1) % members.size());
+        Way way1 = null;
+        Way way2 = null;
+
+        if (m1.member instanceof Way) {
+            way1 = (Way) m1.member;
+        }
+        if (m2.member instanceof Way) {
+            way2 = (Way) m2.member;
+        }
+        if ((way1 != null) && (way2 != null)) {
+            Node way1first = way1.firstNode();
+            Node way1last = way1.lastNode();
+            Node way2first = way2.firstNode();
+            Node way2last = way2.lastNode();
+            if (way1first != null && way2first != null && (way1first == way2first)) {
+                link = WayConnectionType.tail_to_tail;
+            } else if (way1first != null && way2last != null && (way1first == way2last)) {
+                link = WayConnectionType.tail_to_head;
+            } else if (way1last != null && way2first != null && (way1last == way2first)) {
+                link = WayConnectionType.head_to_tail;
+            } else if (way1last != null && way2last != null && (way1last == way2last)) {
+                link = WayConnectionType.head_to_head;
+            }
+        }
+
+        return link;
     }
 }
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableRoleCellRenderer.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableRoleCellRenderer.java	(revision 1822)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTableRoleCellRenderer.java	(revision 1822)
@@ -0,0 +1,21 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.dialogs.relation;
+
+import java.awt.Component;
+
+import javax.swing.JTable;
+
+public class MemberTableRoleCellRenderer extends MemberTableCellRenderer {
+    @Override
+    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
+            int row, int column) {
+
+        reset();
+
+        renderForeground(isSelected);
+        String role = (String) value;
+        renderBackground(getModel(table), null, isSelected);
+        setText(role);
+        return this;
+    }
+}
Index: trunk/src/org/openstreetmap/josm/gui/dialogs/relation/RelationNodeMap.java
===================================================================
--- trunk/src/org/openstreetmap/josm/gui/dialogs/relation/RelationNodeMap.java	(revision 1821)
+++ trunk/src/org/openstreetmap/josm/gui/dialogs/relation/RelationNodeMap.java	(revision 1822)
@@ -1,106 +1,52 @@
 package org.openstreetmap.josm.gui.dialogs.relation;
 
+import java.util.ArrayList;
+
 import org.openstreetmap.josm.data.osm.Node;
-import org.openstreetmap.josm.data.osm.Relation;
 import org.openstreetmap.josm.data.osm.RelationMember;
 import org.openstreetmap.josm.data.osm.Way;
 
 /**
- * A mapping from Node positions to elements in a Relation
- * (currently Nodes and Ways only)
+ * A mapping from Node positions to elements in a Relation (currently Nodes and Ways only)
  * 
  * @author Christiaan Welvaart <cjw@time4t.net>
- *
+ * 
  */
 public class RelationNodeMap {
-    private java.util.HashMap<Node, java.util.TreeSet<Integer>>   points;
-    private java.util.HashMap<Node, Integer>   nodes;
-    private java.util.Vector<Integer>          remaining;
-    private Relation                           relation;
+    private java.util.HashMap<Node, java.util.TreeSet<Integer>> points;
+    private java.util.HashMap<Node, Integer> nodes;
+    private java.util.Vector<Integer> remaining;
+    private ArrayList<RelationMember> members;
 
-    RelationNodeMap(Relation relation)
-    {
-        int     i;
+    RelationNodeMap(ArrayList<RelationMember> members) {
+        int i;
 
-        this.relation = relation;
+        this.members = members;
         points = new java.util.HashMap<Node, java.util.TreeSet<Integer>>();
         nodes = new java.util.HashMap<Node, Integer>();
         remaining = new java.util.Vector<Integer>();
 
-        for (i = 0; i < relation.members.size(); ++i)
-        {
-            RelationMember  m = relation.members.get(i);
+        for (i = 0; i < members.size(); ++i) {
+            RelationMember m = members.get(i);
             if (m.member.incomplete)
-            {
                 // throw an exception?
                 return;
-            }
             add(i, m);
         }
     }
 
-    Integer find(Node node, int current)
-    {
+    Integer find(Node node, int current) {
         Integer result = null;
 
         try {
             result = nodes.get(node);
-            if (result == null)
-            {
+            if (result == null) {
                 result = points.get(node).first();
-                if (relation.members.get(current).member == relation.members.get(result).member)
-                {
+                if (members.get(current).member == members.get(result).member) {
                     result = points.get(node).last();
                 }
             }
-        } catch(NullPointerException f) {}
-        catch(java.util.NoSuchElementException e) {}
-
-        return result;
-    }
-
-    void add(int n, RelationMember m)
-    {
-        try
-        {
-            Way w = (Way)m.member;
-            if (!points.containsKey(w.firstNode()))
-            {
-                points.put(w.firstNode(), new java.util.TreeSet<Integer>());
-            }
-            points.get(w.firstNode()).add(Integer.valueOf(n));
-
-            if (!points.containsKey(w.lastNode()))
-            {
-                points.put(w.lastNode(), new java.util.TreeSet<Integer>());
-            }
-            points.get(w.lastNode()).add(Integer.valueOf(n));
-        }
-        catch(ClassCastException e1)
-        {
-            try
-            {
-                Node        node = (Node)m.member;
-                nodes.put(node, Integer.valueOf(n));
-            }
-            catch(ClassCastException e2)
-            {
-                remaining.add(Integer.valueOf(n));
-            }
-        }
-    }
-
-    boolean remove(int n, RelationMember a)
-    {
-        boolean result;
-
-        try
-        {
-            result = points.get(((Way)a.member).firstNode()).remove(n);
-            result &= points.get(((Way)a.member).lastNode()).remove(n);
-        }
-        catch(ClassCastException e1)
-        {
-            result = (nodes.remove(a.member) != null);
+        } catch (NullPointerException f) {
+        } catch (java.util.NoSuchElementException e) {
         }
 
@@ -108,10 +54,39 @@
     }
 
-    void move(int from, int to)
-    {
-        if (from != to)
-        {
-            RelationMember  b = relation.members.get(from);
-            RelationMember  a = relation.members.get(to);
+    void add(int n, RelationMember m) {
+        if (m.member instanceof Way) {
+            Way w = (Way) m.member;
+            if (!points.containsKey(w.firstNode())) {
+                points.put(w.firstNode(), new java.util.TreeSet<Integer>());
+            }
+            points.get(w.firstNode()).add(Integer.valueOf(n));
+
+            if (!points.containsKey(w.lastNode())) {
+                points.put(w.lastNode(), new java.util.TreeSet<Integer>());
+            }
+            points.get(w.lastNode()).add(Integer.valueOf(n));
+        } else if (m.member instanceof Node) {
+            Node node = (Node) m.member;
+            nodes.put(node, Integer.valueOf(n));
+        } else {
+            remaining.add(Integer.valueOf(n));
+        }
+    }
+
+    boolean remove(int n, RelationMember a) {
+        boolean result;
+        if (a.member instanceof Way) {
+            result = points.get(((Way) a.member).firstNode()).remove(n);
+            result &= points.get(((Way) a.member).lastNode()).remove(n);
+        } else {
+            result = (nodes.remove(a.member) != null);
+        }
+        return result;
+    }
+
+    void move(int from, int to) {
+        if (from != to) {
+            RelationMember b = members.get(from);
+            RelationMember a = members.get(to);
 
             remove(to, b);
@@ -121,30 +96,27 @@
 
     // no node-mapped entries left
-    boolean isEmpty()
-    {
+    boolean isEmpty() {
         return points.isEmpty() && nodes.isEmpty();
     }
 
-    java.util.Vector<Integer> getRemaining()
-    {
+    java.util.Vector<Integer> getRemaining() {
         return remaining;
     }
 
-    Integer pop()
-    {
+    Integer pop() {
+        Node node = null;
         Integer result = null;
 
-        if (!nodes.isEmpty())
-        {
-            result = nodes.values().iterator().next();
-            nodes.remove(result);
-        }
-        else if (!points.isEmpty())
-        {
-            for (java.util.TreeSet<Integer> set : points.values())
-            {
-                if (!set.isEmpty())
-                {
+        if (!nodes.isEmpty()) {
+            node = nodes.keySet().iterator().next();
+            result = nodes.get(node);
+            nodes.remove(node);
+        } else if (!points.isEmpty()) {
+            for (java.util.TreeSet<Integer> set : points.values()) {
+                if (!set.isEmpty()) {
                     result = set.first();
+                    Way w = (Way) members.get(result).member;
+                    points.get(w.firstNode()).remove(result);
+                    points.get(w.lastNode()).remove(result);
                     break;
                 }
@@ -154,4 +126,3 @@
         return result;
     }
-
 }
