Index: /trunk/src/org/openstreetmap/josm/gui/conflict/tags/TagConflictResolverTable.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/conflict/tags/TagConflictResolverTable.java	(revision 9496)
+++ /trunk/src/org/openstreetmap/josm/gui/conflict/tags/TagConflictResolverTable.java	(revision 9497)
@@ -2,41 +2,24 @@
 package org.openstreetmap.josm.gui.conflict.tags;
 
-import java.awt.event.ActionEvent;
-import java.awt.event.KeyEvent;
-
-import javax.swing.AbstractAction;
-import javax.swing.JComponent;
 import javax.swing.JTable;
-import javax.swing.KeyStroke;
 import javax.swing.ListSelectionModel;
 
 import org.openstreetmap.josm.gui.widgets.JosmComboBox;
+import org.openstreetmap.josm.gui.widgets.JosmTable;
 
-public class TagConflictResolverTable extends JTable implements MultiValueCellEditor.NavigationListener {
+public class TagConflictResolverTable extends JosmTable implements MultiValueCellEditor.NavigationListener {
 
-    private SelectNextColumnCellAction selectNextColumnCellAction;
-    private SelectPreviousColumnCellAction selectPreviousColumnCellAction;
-
+    /**
+     * Constructs a new {@code TagConflictResolverTable}.
+     * @param model table model
+     */
     public TagConflictResolverTable(TagConflictResolverModel model) {
         super(model, new TagConflictResolverColumnModel());
-        build();
-    }
 
-    protected final void build() {
         setAutoResizeMode(JTable.AUTO_RESIZE_ALL_COLUMNS);
         setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
         putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
 
-        // make ENTER behave like TAB
-        //
-        getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
-                KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, false), "selectNextColumnCell");
-
-        // install custom navigation actions
-        //
-        selectNextColumnCellAction = new SelectNextColumnCellAction();
-        selectPreviousColumnCellAction = new SelectPreviousColumnCellAction();
-        getActionMap().put("selectNextColumnCell", selectNextColumnCellAction);
-        getActionMap().put("selectPreviousColumnCell", selectPreviousColumnCellAction);
+        installCustomNavigation(2);
 
         ((MultiValueCellEditor) getColumnModel().getColumn(2).getCellEditor()).addNavigationListener(this);
@@ -45,78 +28,12 @@
     }
 
-    /**
-     * Action to be run when the user navigates to the next cell in the table, for instance by
-     * pressing TAB or ENTER. The action alters the standard navigation path from cell to cell: <ul>
-     * <li>it jumps over cells in the first column</li> <li>it automatically add a new empty row
-     * when the user leaves the last cell in the table</li></ul>
-     *
-     *
-     */
-    class SelectNextColumnCellAction extends AbstractAction {
-        @Override
-        public void actionPerformed(ActionEvent e) {
-            run();
-        }
-
-        public void run() {
-            int col = getSelectedColumn();
-            int row = getSelectedRow();
-            if (getCellEditor() != null) {
-                getCellEditor().stopCellEditing();
-            }
-
-            if (col == 2 && row < getRowCount() - 1) {
-                row++;
-            } else if (row < getRowCount() - 1) {
-                col = 2;
-                row++;
-            }
-            changeSelection(row, col, false, false);
-            if (editCellAt(getSelectedRow(), getSelectedColumn())) {
-                getEditorComponent().requestFocusInWindow();
-            }
-        }
-    }
-
-    /**
-     * Action to be run when the user navigates to the previous cell in the table, for instance by
-     * pressing Shift-TAB
-     *
-     */
-    class SelectPreviousColumnCellAction extends AbstractAction {
-
-        @Override
-        public void actionPerformed(ActionEvent e) {
-            run();
-        }
-
-        public void run() {
-            int col = getSelectedColumn();
-            int row = getSelectedRow();
-            if (getCellEditor() != null) {
-                getCellEditor().stopCellEditing();
-            }
-
-            if (col <= 0 && row <= 0) {
-                // change nothing
-            } else if (row > 0) {
-                col = 2;
-                row--;
-            }
-            changeSelection(row, col, false, false);
-            if (editCellAt(getSelectedRow(), getSelectedColumn())) {
-                getEditorComponent().requestFocusInWindow();
-            }
-        }
-    }
-
     @Override
     public void gotoNextDecision() {
-        selectNextColumnCellAction.run();
+        selectNextColumnCellAction.actionPerformed(null);
     }
 
     @Override
     public void gotoPreviousDecision() {
-        selectPreviousColumnCellAction.run();
+        selectPreviousColumnCellAction.actionPerformed(null);
     }
 }
Index: /trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTable.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTable.java	(revision 9496)
+++ /trunk/src/org/openstreetmap/josm/gui/dialogs/relation/MemberTable.java	(revision 9497)
@@ -7,7 +7,5 @@
 import java.awt.Dimension;
 import java.awt.GraphicsEnvironment;
-import java.awt.KeyboardFocusManager;
 import java.awt.event.ActionEvent;
-import java.awt.event.KeyEvent;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -17,9 +15,7 @@
 import javax.swing.AbstractAction;
 import javax.swing.DropMode;
-import javax.swing.JComponent;
 import javax.swing.JPopupMenu;
 import javax.swing.JTable;
 import javax.swing.JViewport;
-import javax.swing.KeyStroke;
 import javax.swing.ListSelectionModel;
 import javax.swing.SwingUtilities;
@@ -61,11 +57,5 @@
         setLayer(layer);
         model.addMemberModelListener(this);
-        init();
-    }
-
-    /**
-     * initialize the table
-     */
-    protected void init() {
+
         MemberRoleCellEditor ce = (MemberRoleCellEditor) getColumnModel().getColumn(0).getCellEditor();
         setRowHeight(ce.getEditor().getPreferredSize().height);
@@ -74,15 +64,6 @@
         putClientProperty("terminateEditOnFocusLost", Boolean.TRUE);
 
-        // make ENTER behave like TAB
-        //
-        getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
-                KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, false), "selectNextColumnCell");
-
+        installCustomNavigation(0);
         initHighlighting();
-
-        // install custom navigation actions
-        //
-        getActionMap().put("selectNextColumnCell", new SelectNextColumnCellAction());
-        getActionMap().put("selectPreviousColumnCell", new SelectPreviousColumnCellAction());
 
         if (!GraphicsEnvironment.isHeadless()) {
@@ -164,62 +145,4 @@
     }
 
-    /**
-     * Action to be run when the user navigates to the next cell in the table, for instance by
-     * pressing TAB or ENTER. The action alters the standard navigation path from cell to cell: <ul>
-     * <li>it jumps over cells in the first column</li> <li>it automatically add a new empty row
-     * when the user leaves the last cell in the table</li></ul>
-     */
-    class SelectNextColumnCellAction extends AbstractAction {
-        @Override
-        public void actionPerformed(ActionEvent e) {
-            run();
-        }
-
-        public void run() {
-            int col = getSelectedColumn();
-            int row = getSelectedRow();
-            if (getCellEditor() != null) {
-                getCellEditor().stopCellEditing();
-            }
-
-            if (col == 0 && row < getRowCount() - 1) {
-                row++;
-            } else if (row < getRowCount() - 1) {
-                col = 0;
-                row++;
-            } else {
-                // go to next component, no more rows in this table
-                KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
-                manager.focusNextComponent();
-                return;
-            }
-            changeSelection(row, col, false, false);
-        }
-    }
-
-    /**
-     * Action to be run when the user navigates to the previous cell in the table, for instance by
-     * pressing Shift-TAB
-     */
-    private class SelectPreviousColumnCellAction extends AbstractAction {
-
-        @Override
-        public void actionPerformed(ActionEvent e) {
-            int col = getSelectedColumn();
-            int row = getSelectedRow();
-            if (getCellEditor() != null) {
-                getCellEditor().stopCellEditing();
-            }
-
-            if (col <= 0 && row <= 0) {
-                // change nothing
-            } else if (row > 0) {
-                col = 0;
-                row--;
-            }
-            changeSelection(row, col, false, false);
-        }
-    }
-
     @Override
     public void unlinkAsListener() {
Index: /trunk/src/org/openstreetmap/josm/gui/widgets/JosmTable.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/widgets/JosmTable.java	(revision 9497)
+++ /trunk/src/org/openstreetmap/josm/gui/widgets/JosmTable.java	(revision 9497)
@@ -0,0 +1,107 @@
+// License: GPL. For details, see LICENSE file.
+package org.openstreetmap.josm.gui.widgets;
+
+import java.awt.KeyboardFocusManager;
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+
+import javax.swing.AbstractAction;
+import javax.swing.JComponent;
+import javax.swing.JTable;
+import javax.swing.KeyStroke;
+import javax.swing.ListSelectionModel;
+import javax.swing.table.TableColumnModel;
+import javax.swing.table.TableModel;
+
+/**
+ * Generic table offering custom cell navigation features.
+ * @since 9497
+ */
+public abstract class JosmTable extends JTable {
+
+    private int colEnd;
+
+    protected SelectNextColumnCellAction selectNextColumnCellAction;
+    protected SelectPreviousColumnCellAction selectPreviousColumnCellAction;
+
+    protected JosmTable(TableModel dm, TableColumnModel cm) {
+        this(dm, cm, null);
+    }
+
+    protected JosmTable(TableModel dm, TableColumnModel cm, ListSelectionModel sm) {
+        super(dm, cm, sm);
+    }
+
+    protected void installCustomNavigation(int colEnd) {
+        // make ENTER behave like TAB
+        getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
+                KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, false), "selectNextColumnCell");
+
+        // install custom navigation actions
+        this.colEnd = colEnd;
+        selectNextColumnCellAction = new SelectNextColumnCellAction();
+        selectPreviousColumnCellAction = new SelectPreviousColumnCellAction();
+        getActionMap().put("selectNextColumnCell", selectNextColumnCellAction);
+        getActionMap().put("selectPreviousColumnCell", selectPreviousColumnCellAction);
+    }
+
+    /**
+     * Action to be run when the user navigates to the next cell in the table, for instance by
+     * pressing TAB or ENTER. The action alters the standard navigation path from cell to cell: <ul>
+     * <li>it jumps over cells in the first column</li>
+     * <li>it automatically add a new empty row when the user leaves the last cell in the table</li></ul>
+     */
+    protected class SelectNextColumnCellAction extends AbstractAction {
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            int col = getSelectedColumn();
+            int row = getSelectedRow();
+            if (getCellEditor() != null) {
+                getCellEditor().stopCellEditing();
+            }
+
+            if (col == colEnd && row < getRowCount() - 1) {
+                row++;
+            } else if (row < getRowCount() - 1) {
+                col = colEnd;
+                row++;
+            } else {
+                // go to next component, no more rows in this table
+                KeyboardFocusManager manager = KeyboardFocusManager.getCurrentKeyboardFocusManager();
+                manager.focusNextComponent();
+                return;
+            }
+            changeSelection(row, col, false, false);
+            if (editCellAt(getSelectedRow(), getSelectedColumn())) {
+                getEditorComponent().requestFocusInWindow();
+            }
+        }
+    }
+
+    /**
+     * Action to be run when the user navigates to the previous cell in the table, for instance by
+     * pressing Shift-TAB
+     */
+    protected class SelectPreviousColumnCellAction extends AbstractAction {
+
+        @Override
+        public void actionPerformed(ActionEvent e) {
+            int col = getSelectedColumn();
+            int row = getSelectedRow();
+            if (getCellEditor() != null) {
+                getCellEditor().stopCellEditing();
+            }
+
+            if (col <= 0 && row <= 0) {
+                // change nothing
+            } else if (row > 0) {
+                col = colEnd;
+                row--;
+            }
+            changeSelection(row, col, false, false);
+            if (editCellAt(getSelectedRow(), getSelectedColumn())) {
+                getEditorComponent().requestFocusInWindow();
+            }
+        }
+    }
+}
Index: /trunk/src/org/openstreetmap/josm/gui/widgets/OsmPrimitivesTable.java
===================================================================
--- /trunk/src/org/openstreetmap/josm/gui/widgets/OsmPrimitivesTable.java	(revision 9496)
+++ /trunk/src/org/openstreetmap/josm/gui/widgets/OsmPrimitivesTable.java	(revision 9497)
@@ -6,5 +6,4 @@
 
 import javax.swing.JPopupMenu;
-import javax.swing.JTable;
 import javax.swing.ListSelectionModel;
 import javax.swing.SwingUtilities;
@@ -16,5 +15,9 @@
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 
-public abstract class OsmPrimitivesTable extends JTable {
+/**
+ * Table displaying OSM primitives.
+ * @since 5297
+ */
+public abstract class OsmPrimitivesTable extends JosmTable {
 
     /**
@@ -27,12 +30,10 @@
     private ZoomToAction zoomToAction;
 
-    public final OsmDataLayer getLayer() {
-        return layer;
-    }
-
-    public final void setLayer(OsmDataLayer layer) {
-        this.layer = layer;
-    }
-
+    /**
+     * Constructs a new {@code OsmPrimitivesTable}.
+     * @param dm table model
+     * @param cm column model
+     * @param sm selection model
+     */
     public OsmPrimitivesTable(OsmPrimitivesTableModel dm, TableColumnModel cm, ListSelectionModel sm) {
         super(dm, cm, sm);
@@ -41,6 +42,26 @@
     }
 
+    /**
+     * Returns the table model.
+     * @return the table model
+     */
     public OsmPrimitivesTableModel getOsmPrimitivesTableModel() {
         return (OsmPrimitivesTableModel) getModel();
+    }
+
+    /**
+     * Returns the data layer.
+     * @return the data layer
+     */
+    public final OsmDataLayer getLayer() {
+        return layer;
+    }
+
+    /**
+     * Sets the data layer.
+     * @param layer the data layer
+     */
+    public final void setLayer(OsmDataLayer layer) {
+        this.layer = layer;
     }
 
@@ -72,4 +93,10 @@
     }
 
+    /**
+     * Returns primitive at the specified row.
+     * @param row table row
+     * @param layer unused in this implementation, can be useful for subclasses
+     * @return primitive at the specified row
+     */
     public OsmPrimitive getPrimitiveInLayer(int row, OsmDataLayer layer) {
         return getOsmPrimitivesTableModel().getReferredPrimitive(row);
