Index: /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/preset/ui/IPresetSelectorListener.java
===================================================================
--- /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/preset/ui/IPresetSelectorListener.java	(revision 14328)
+++ /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/preset/ui/IPresetSelectorListener.java	(revision 14328)
@@ -0,0 +1,8 @@
+package org.openstreetmap.josm.plugins.tageditor.preset.ui;
+
+import org.openstreetmap.josm.plugins.tageditor.preset.Item;
+
+public interface IPresetSelectorListener {
+
+	public void itemSelected(Item item);
+}
Index: /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/preset/ui/NameIconCellRenderer.java
===================================================================
--- /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/preset/ui/NameIconCellRenderer.java	(revision 14328)
+++ /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/preset/ui/NameIconCellRenderer.java	(revision 14328)
@@ -0,0 +1,45 @@
+package org.openstreetmap.josm.plugins.tageditor.preset.ui;
+
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Font;
+import java.util.logging.Logger;
+
+import javax.swing.JLabel;
+import javax.swing.JTable;
+import javax.swing.table.TableCellRenderer;
+
+import org.openstreetmap.josm.plugins.tageditor.preset.INameIconProvider;
+
+
+
+public class NameIconCellRenderer extends JLabel implements TableCellRenderer {
+	
+	private static Logger logger = Logger.getLogger(NameIconCellRenderer.class.getName());
+	public static final Color BG_COLOR_SELECTED = new Color(143,170,255);
+	
+
+	protected void init() {
+		setOpaque(true);
+		setFont(new Font("SansSerif",Font.PLAIN,10));
+	}
+	
+	public NameIconCellRenderer() {
+		init();
+	}
+	
+	@Override
+	public Component getTableCellRendererComponent(JTable table, Object value,
+			boolean isSelected, boolean hasFocus, int rowIndex, int colIndex) {
+	
+		if (isSelected) {
+			setBackground(BG_COLOR_SELECTED);			
+		} else  {
+			setBackground(Color.WHITE);
+		}
+		INameIconProvider provider = (INameIconProvider) value;
+		setText(provider.getName());
+		setIcon(provider.getIcon());
+		return this; 
+	}
+}
Index: /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/preset/ui/PresetsTable.java
===================================================================
--- /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/preset/ui/PresetsTable.java	(revision 14328)
+++ /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/preset/ui/PresetsTable.java	(revision 14328)
@@ -0,0 +1,47 @@
+package org.openstreetmap.josm.plugins.tageditor.preset.ui;
+
+import javax.swing.JTable;
+import javax.swing.ListSelectionModel;
+import javax.swing.table.TableColumnModel;
+import javax.swing.table.TableModel;
+
+
+public class PresetsTable extends JTable {
+
+	/**
+	 * initialize the table 
+	 */
+	protected void init() {				
+		setAutoResizeMode(JTable.AUTO_RESIZE_OFF);		
+		setRowSelectionAllowed(true);
+		setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+		setRowHeight(18); // icon height (=16) + minimal border
+		
+	}
+	
+	public PresetsTable(TableModel model, TableColumnModel columnModel) {
+		super(model,columnModel);
+		init();
+	}
+	
+	/**
+	 * adjusts the width of the columns for the tag name and the tag value
+	 * to the width of the scroll panes viewport.
+	 * 
+	 * Note: {@see #getPreferredScrollableViewportSize()} did not work as expected
+	 * 
+	 * @param scrollPaneWidth the width of the scroll panes viewport
+	 */
+	public void adjustColumnWidth(int scrollPaneWidth) {
+		TableColumnModel tcm = getColumnModel();
+		int width = scrollPaneWidth;
+		width = width / 2;
+		if (width > 0) {
+			tcm.getColumn(0).setMinWidth(width);
+			tcm.getColumn(0).setMaxWidth(width);
+			tcm.getColumn(1).setMinWidth(width);
+			tcm.getColumn(1).setMaxWidth(width);			
+		}
+	}
+
+}
Index: /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/preset/ui/PresetsTableColumnModel.java
===================================================================
--- /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/preset/ui/PresetsTableColumnModel.java	(revision 14328)
+++ /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/preset/ui/PresetsTableColumnModel.java	(revision 14328)
@@ -0,0 +1,35 @@
+package org.openstreetmap.josm.plugins.tageditor.preset.ui;
+
+import javax.swing.table.DefaultTableColumnModel;
+import javax.swing.table.TableCellRenderer;
+import javax.swing.table.TableColumn;
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+public class PresetsTableColumnModel extends DefaultTableColumnModel  {
+
+	protected void createColumns() {
+		TableCellRenderer renderer = new NameIconCellRenderer();
+		
+		TableColumn col = null;
+		
+		// column 0 - Group   
+		col = new TableColumn(0);
+		col.setHeaderValue(tr("Group"));
+		col.setResizable(true);
+		col.setCellRenderer(renderer);
+		addColumn(col);
+		
+		// column 1 - Item   
+		col = new TableColumn(1);
+		col.setHeaderValue(tr("Item"));
+		col.setResizable(true);
+		col.setCellRenderer(renderer);
+		addColumn(col);
+
+	}
+
+	public PresetsTableColumnModel() {
+		createColumns();
+	}
+	
+}
Index: /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/preset/ui/PresetsTableModel.java
===================================================================
--- /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/preset/ui/PresetsTableModel.java	(revision 14328)
+++ /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/preset/ui/PresetsTableModel.java	(revision 14328)
@@ -0,0 +1,146 @@
+package org.openstreetmap.josm.plugins.tageditor.preset.ui;
+
+import java.util.ArrayList;
+import java.util.logging.Logger;
+
+import javax.swing.event.TableModelListener;
+import javax.swing.table.AbstractTableModel;
+
+import org.openstreetmap.josm.plugins.tageditor.preset.Group;
+import org.openstreetmap.josm.plugins.tageditor.preset.Item;
+import org.openstreetmap.josm.plugins.tageditor.preset.Presets;
+
+
+public class PresetsTableModel extends AbstractTableModel  {
+
+	private static final Logger logger = Logger.getLogger(PresetsTableModel.class.getName());
+	
+	 private ArrayList<TableModelListener> listeners = new ArrayList<TableModelListener>();
+	 private ArrayList<Item> items = new ArrayList<Item>();
+	 private ArrayList<Item> visibleItems = new ArrayList<Item>();
+	 private Presets presets = null;
+	 
+	 
+	 protected void initModelFromPresets(Presets presets) {
+		for(Group group: presets.getGroups()) {
+			for(Item item: group.getItems()) {
+				items.add(item);
+				visibleItems.add(item);
+			}
+		}
+	 }
+	 
+	
+	 public PresetsTableModel() {
+	 }
+	 
+	 public PresetsTableModel(Presets presets) {
+		 setPresets(presets);
+	 }
+	 
+	
+	public Presets getPresets() {
+		return presets;
+	}
+
+
+
+	public void setPresets(Presets presets) {
+		this.presets = presets;
+		initModelFromPresets(presets);
+		fireTableDataChanged();
+	}
+
+
+
+	@Override
+	public void addTableModelListener(TableModelListener l) {
+		synchronized(listeners) {
+			if (l == null) {
+				return;
+			}
+			if (!listeners.contains(l)) {
+				listeners.add(l);
+			}
+		}
+	}
+
+	@Override
+	public Class<?> getColumnClass(int columnIndex) {
+		return String.class;
+	}
+
+	@Override
+	public int getColumnCount() {
+		return 2;
+	}
+
+
+	@Override
+	public int getRowCount() {
+		return visibleItems.size();
+	}
+
+	@Override
+	public Object getValueAt(int rowIndex, int columnIndex) {
+		Item item = visibleItems.get(rowIndex);
+		switch(columnIndex) {
+			case 0: return item.getParent();
+			case 1: return item;
+			default: return "unknown"; 
+		
+		}
+	}
+
+	@Override
+	public boolean isCellEditable(int rowIndex, int columnIndex) {
+		return false;
+	}
+
+	@Override
+	public void removeTableModelListener(TableModelListener l) {
+		synchronized (listeners) {
+			if (listeners.contains(l)) {
+				listeners.remove(l);
+			}
+		}		
+	}
+
+	@Override
+	public void setValueAt(Object value, int rowIndex, int columnIndex) {
+		// do nothing. No editing allowed 		
+	}
+
+	
+	public Item getVisibleItem(int idx) {
+		if (idx < 0 || idx >= this.visibleItems.size()) {
+			throw new IndexOutOfBoundsException("index out of bounds. idx=" + idx);
+		}
+		return visibleItems.get(idx);
+	}
+	
+	
+	
+	public void filter(String filter) {
+		synchronized(this) {
+			if (filter == null || filter.trim().equals("")) {
+				visibleItems.clear();
+				for(Item item: items) {
+					visibleItems.add(item);
+				}
+			} else { 
+				visibleItems.clear();
+				filter = filter.toLowerCase();
+				for(Item item: items) {
+					if (    (item.getName() != null && item.getName().toLowerCase().trim().startsWith(filter))
+					     || (item.getParent().getName() != null && item.getParent().getName().toLowerCase().trim().startsWith(filter))) {
+						visibleItems.add(item);
+					}
+				}	
+			}
+			fireTableDataChanged();
+			fireTableStructureChanged();
+		}
+		
+	}
+}
Index: /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/preset/ui/TabularPresetSelector.java
===================================================================
--- /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/preset/ui/TabularPresetSelector.java	(revision 14328)
+++ /applications/editors/josm/plugins/tageditor/src/org/openstreetmap/josm/plugins/tageditor/preset/ui/TabularPresetSelector.java	(revision 14328)
@@ -0,0 +1,293 @@
+package org.openstreetmap.josm.plugins.tageditor.preset.ui;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.ComponentAdapter;
+import java.awt.event.ComponentEvent;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.ArrayList;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.JButton;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.JTextField;
+import javax.swing.KeyStroke;
+import javax.swing.ScrollPaneConstants;
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
+
+import org.openstreetmap.josm.plugins.tageditor.preset.Item;
+import org.openstreetmap.josm.plugins.tageditor.preset.Presets;
+
+
+public class TabularPresetSelector extends JPanel {
+
+	private PresetsTable presetsTable = null;
+	private JTextField   tfFilter = null;
+	private ArrayList<IPresetSelectorListener> listeners = new ArrayList<IPresetSelectorListener>();
+	private JScrollPane scrollPane;
+	private JButton btnApply;
+	
+	
+	protected JPanel buildFilterPanel() {
+		JPanel pnl = new JPanel();
+		JLabel lbl = new JLabel(tr("Search: "));
+		pnl.setLayout(new FlowLayout(FlowLayout.LEFT));
+		tfFilter = new JTextField(20);
+		pnl.add(lbl);
+		pnl.add(tfFilter,BorderLayout.CENTER);
+		JButton btn = new JButton(tr("Filter"));
+		pnl.add(btn);
+		btn.addActionListener(
+			new ActionListener() {
+				@Override
+				public void actionPerformed(ActionEvent e) {
+					filter(tfFilter.getText());						
+				}
+				
+			}
+		);
+		btn = new JButton(tr("Clear"));
+		pnl.add(btn);
+		btn.addActionListener(
+				new ActionListener() {
+					@Override
+					public void actionPerformed(ActionEvent e) {
+						tfFilter.setText("");
+						tfFilter.requestFocus();
+					}					
+				}
+			);		
+		return pnl;
+	}
+	
+	
+	
+	protected JScrollPane buildPresetGrid() {
+					
+		presetsTable = new PresetsTable(new PresetsTableModel(),new PresetsTableColumnModel());
+		
+		scrollPane = new JScrollPane(presetsTable);
+		
+		scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
+		scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED);
+		
+		// this adapters ensures that the width of the tag table columns is adjusted
+		// to the width of the scroll pane viewport. Also tried to overwrite 
+		// 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();
+	                    presetsTable.adjustColumnWidth(d.width);
+                    }
+				}
+		);
+		
+		// add the double click listener 
+		//
+		presetsTable.addMouseListener(new DoubleClickAdapter());
+		
+		// replace Enter action. apply the current preset on enter
+		//
+		presetsTable.unregisterKeyboardAction(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0));
+		ActionListener enterAction = new ActionListener() {
+			public void actionPerformed(ActionEvent e) {
+				int rowNum = presetsTable.getSelectedRow();
+				if (rowNum >= 0) {
+					Item item = getModel().getVisibleItem(rowNum);
+					fireItemSelected(item);
+				}
+			}
+		};
+		
+		presetsTable.registerKeyboardAction(
+			enterAction, 
+			"Enter", 
+			KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0), 
+			JComponent.WHEN_FOCUSED
+		);
+		
+		return scrollPane;
+	}
+	
+	protected JPanel buildControlButtonPanel() {
+		JPanel pnl = new JPanel();
+		pnl.setLayout(new FlowLayout(FlowLayout.LEFT));
+		btnApply = new JButton("Apply");
+		pnl.add(btnApply);
+		btnApply.addActionListener(
+			new ActionListener() {
+				@Override
+				public void actionPerformed(ActionEvent arg0) {
+					int row = presetsTable.getSelectedRow();
+					if (row >=0) {
+						Item item = getModel().getVisibleItem(row);
+						fireItemSelected(item);
+					}
+				}				
+			}
+		);
+		return pnl;		
+	}
+	
+	protected void build() {
+		setLayout(new BorderLayout());
+		add(buildFilterPanel(), BorderLayout.NORTH);
+		add(buildPresetGrid(), BorderLayout.CENTER);
+		add(buildControlButtonPanel(), BorderLayout.SOUTH);
+		
+		// wire the text field for filter expressions to the prests
+		// table
+		//
+		tfFilter.getDocument().addDocumentListener(
+				new DocumentListener() {
+					@Override
+					public void changedUpdate(DocumentEvent arg0) {
+						onUpdate();
+					}
+
+					@Override
+					public void insertUpdate(DocumentEvent arg0) {
+						onUpdate();
+					}
+
+					@Override
+					public void removeUpdate(DocumentEvent arg0) {
+						onUpdate();
+					}
+				
+					protected void onUpdate() {
+					    filter(tfFilter.getText());
+					}
+				}
+			);
+		
+		tfFilter.addActionListener(
+				new ActionListener() {
+					@Override
+					public void actionPerformed(ActionEvent e) {
+						filter(tfFilter.getText());
+					}					
+				}
+		);
+		
+		// wire the apply button to the selection model of the preset table
+		// 
+		presetsTable.getSelectionModel().addListSelectionListener(
+			new ListSelectionListener() {
+	
+				@Override
+				public void valueChanged(ListSelectionEvent e) {
+					btnApply.setEnabled(presetsTable.getSelectedRowCount() != 0);
+				}
+			}
+		);
+		
+	
+		// load the set of presets and bind them to the preset table
+		//
+		Presets.initPresets();
+		bindTo(Presets.getPresets());
+		presetsTable.getSelectionModel().clearSelection();
+		btnApply.setEnabled(false);
+	
+	}
+	
+	public void bindTo(Presets presets) {
+		PresetsTableModel model = (PresetsTableModel)presetsTable.getModel();
+		model.setPresets(presets);
+	}
+	
+	public TabularPresetSelector() {
+		build();
+	}
+
+	public void addPresetSelectorListener(IPresetSelectorListener listener) {
+		synchronized(this.listeners) {
+			if (listener != null && ! listeners.contains(listener)) {
+				listeners.add(listener);
+			}
+		}
+	}
+	
+	public void removePresetSelectorListener(IPresetSelectorListener listener) {
+		synchronized(this.listeners) {
+			if (listener != null) {
+				listeners.remove(listener);
+			}
+		}
+	}
+	
+	protected void fireItemSelected(Item item) {
+		synchronized(this.listeners) {
+			for(IPresetSelectorListener listener: listeners) {
+				listener.itemSelected(item);
+			}
+		}
+	}
+	
+	
+
+	
+	private class DoubleClickAdapter extends MouseAdapter {
+		@Override
+		public void mouseClicked(MouseEvent e) {
+			if (e.getClickCount() == 2) {
+				int rowNum = presetsTable.rowAtPoint(e.getPoint());
+				Item item = getModel().getVisibleItem(rowNum);
+				fireItemSelected(item);
+			}
+		}
+	}
+	
+	
+	public void filter(String filter) {
+		presetsTable.getSelectionModel().clearSelection();
+		getModel().filter(filter);
+		
+		presetsTable.scrollRectToVisible(presetsTable.getCellRect(0, 0, false));
+		
+		// we change the number of rows by applying a filter condition. Because
+		// the table is embedded in a JScrollPane which again may be embedded in
+		// other JScrollPanes or JSplitPanes it seems that we have to recalculate 
+		// the layout and repaint the component tree. Maybe there is a more efficient way
+		// to keep the GUI in sync with the number of rows in table. By trial
+		// and error I ended up with the following lines. 
+		// 
+		Component c = presetsTable;
+		while(c != null) {
+			c.doLayout();
+			c.repaint();
+			c = c.getParent();
+		}
+	}
+	
+	
+	protected PresetsTableModel getModel() {
+		return (PresetsTableModel)presetsTable.getModel();
+	}
+	
+	public void installKeyAction(Action a) {
+		getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put((KeyStroke)a.getValue(AbstractAction.ACCELERATOR_KEY), a.getValue(AbstractAction.NAME));
+		getActionMap().put(a.getValue(AbstractAction.NAME), a);
+
+	}
+	
+}
