Index: /src/org/openstreetmap/josm/Main.java
===================================================================
--- /src/org/openstreetmap/josm/Main.java	(revision 293)
+++ /src/org/openstreetmap/josm/Main.java	(revision 294)
@@ -52,5 +52,5 @@
 import org.openstreetmap.josm.gui.layer.OsmDataLayer;
 import org.openstreetmap.josm.gui.layer.OsmDataLayer.CommandQueueListener;
-import org.openstreetmap.josm.gui.preferences.AnnotationPresetPreference;
+import org.openstreetmap.josm.gui.preferences.TaggingPresetPreference;
 import org.openstreetmap.josm.gui.preferences.ToolbarPreferences;
 import org.openstreetmap.josm.plugins.PluginException;
@@ -192,5 +192,5 @@
 		contentPane.getActionMap().put("Help", menu.help);
 
-		AnnotationPresetPreference.initialize();
+		TaggingPresetPreference.initialize();
 
 		toolbar.refreshToolbarControl();
Index: /src/org/openstreetmap/josm/gui/dialogs/PropertiesDialog.java
===================================================================
--- /src/org/openstreetmap/josm/gui/dialogs/PropertiesDialog.java	(revision 293)
+++ /src/org/openstreetmap/josm/gui/dialogs/PropertiesDialog.java	(revision 294)
@@ -48,8 +48,8 @@
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.gui.MapFrame;
-import org.openstreetmap.josm.gui.annotation.AnnotationCellRenderer;
-import org.openstreetmap.josm.gui.annotation.AnnotationPreset;
-import org.openstreetmap.josm.gui.annotation.ForwardActionListener;
-import org.openstreetmap.josm.gui.preferences.AnnotationPresetPreference;
+import org.openstreetmap.josm.gui.preferences.TaggingPresetPreference;
+import org.openstreetmap.josm.gui.tagging.TaggingCellRenderer;
+import org.openstreetmap.josm.gui.tagging.ForwardActionListener;
+import org.openstreetmap.josm.gui.tagging.TaggingPreset;
 import org.openstreetmap.josm.tools.AutoCompleteComboBox;
 import org.openstreetmap.josm.tools.GBC;
@@ -269,5 +269,5 @@
 	 */
 	private final JTable propertyTable = new JTable(data);
-	public JComboBox annotationPresets = new JComboBox();
+	public JComboBox taggingPresets = new JComboBox();
 
 
@@ -278,24 +278,24 @@
 		super(tr("Properties"), "propertiesdialog", tr("Properties for selected objects."), KeyEvent.VK_P, 150);
 
-		if (AnnotationPresetPreference.annotationPresets.size() > 0) {
+		if (TaggingPresetPreference.taggingPresets.size() > 0) {
 			Vector<ActionListener> allPresets = new Vector<ActionListener>();
-			for (final AnnotationPreset p : AnnotationPresetPreference.annotationPresets)
+			for (final TaggingPreset p : TaggingPresetPreference.taggingPresets)
 				allPresets.add(new ForwardActionListener(this, p));
 
-			allPresets.add(0, new ForwardActionListener(this, new AnnotationPreset()));
-			annotationPresets.setModel(new DefaultComboBoxModel(allPresets));
+			allPresets.add(0, new ForwardActionListener(this, new TaggingPreset()));
+			taggingPresets.setModel(new DefaultComboBoxModel(allPresets));
 			JPanel north = new JPanel(new GridBagLayout());
 			north.add(getComponent(0),GBC.eol().fill(GBC.HORIZONTAL));
-			north.add(annotationPresets,GBC.eol().fill(GBC.HORIZONTAL));
+			north.add(taggingPresets,GBC.eol().fill(GBC.HORIZONTAL));
 			add(north, BorderLayout.NORTH);
 		}
-		annotationPresets.addActionListener(new ActionListener(){
+		taggingPresets.addActionListener(new ActionListener(){
 			public void actionPerformed(ActionEvent e) {
-				AnnotationPreset preset = ((ForwardActionListener)annotationPresets.getSelectedItem()).preset;
+				TaggingPreset preset = ((ForwardActionListener)taggingPresets.getSelectedItem()).preset;
 				preset.actionPerformed(e);
-				annotationPresets.setSelectedItem(null);
+				taggingPresets.setSelectedItem(null);
 			}
 		});
-		annotationPresets.setRenderer(new AnnotationCellRenderer());
+		taggingPresets.setRenderer(new TaggingCellRenderer());
 
 		data.setColumnIdentifiers(new String[]{tr("Key"),tr("Value")});
Index: c/org/openstreetmap/josm/gui/preferences/AnnotationPresetPreference.java
===================================================================
--- /src/org/openstreetmap/josm/gui/preferences/AnnotationPresetPreference.java	(revision 293)
+++ 	(revision )
@@ -1,105 +1,0 @@
-package org.openstreetmap.josm.gui.preferences;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.GridBagLayout;
-import java.awt.event.ActionEvent;
-import java.awt.event.ActionListener;
-import java.util.Collection;
-import java.util.StringTokenizer;
-
-import javax.swing.Box;
-import javax.swing.DefaultListModel;
-import javax.swing.JButton;
-import javax.swing.JLabel;
-import javax.swing.JList;
-import javax.swing.JOptionPane;
-import javax.swing.JPanel;
-import javax.swing.JScrollPane;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.gui.annotation.AnnotationPreset;
-import org.openstreetmap.josm.tools.GBC;
-
-public class AnnotationPresetPreference implements PreferenceSetting {
-
-	public static Collection<AnnotationPreset> annotationPresets;
-	private JList annotationSources;
-
-	public void addGui(final PreferenceDialog gui) {
-		annotationSources = new JList(new DefaultListModel());
-		String annos = Main.pref.get("annotation.sources");
-		StringTokenizer st = new StringTokenizer(annos, ";");
-		while (st.hasMoreTokens())
-			((DefaultListModel)annotationSources.getModel()).addElement(st.nextToken());
-
-		JButton addAnno = new JButton(tr("Add"));
-		addAnno.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				String source = JOptionPane.showInputDialog(Main.parent, tr("Annotation preset source"));
-				if (source == null)
-					return;
-				((DefaultListModel)annotationSources.getModel()).addElement(source);
-				gui.requiresRestart = true;
-			}
-		});
-
-		JButton editAnno = new JButton(tr("Edit"));
-		editAnno.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				if (annotationSources.getSelectedIndex() == -1)
-					JOptionPane.showMessageDialog(Main.parent, tr("Please select the row to edit."));
-				else {
-					String source = JOptionPane.showInputDialog(Main.parent, tr("Annotation preset source"), annotationSources.getSelectedValue());
-					if (source == null)
-						return;
-					((DefaultListModel)annotationSources.getModel()).setElementAt(source, annotationSources.getSelectedIndex());
-					gui.requiresRestart = true;
-				}
-			}
-		});
-
-		JButton deleteAnno = new JButton(tr("Delete"));
-		deleteAnno.addActionListener(new ActionListener(){
-			public void actionPerformed(ActionEvent e) {
-				if (annotationSources.getSelectedIndex() == -1)
-					JOptionPane.showMessageDialog(Main.parent, tr("Please select the row to delete."));
-				else {
-					((DefaultListModel)annotationSources.getModel()).remove(annotationSources.getSelectedIndex());
-					gui.requiresRestart = true;
-				}
-			}
-		});
-		annotationSources.setVisibleRowCount(3);
-
-		annotationSources.setToolTipText(tr("The sources (url or filename) of annotation preset definition files. See http://josm.eigenheimstrasse.de/wiki/AnnotationPresets for help."));
-		addAnno.setToolTipText(tr("Add a new annotation preset source to the list."));
-		deleteAnno.setToolTipText(tr("Delete the selected source from the list."));
-
-		gui.map.add(new JLabel(tr("Annotation preset sources")), GBC.eol().insets(0,5,0,0));
-		gui.map.add(new JScrollPane(annotationSources), GBC.eol().fill(GBC.BOTH));
-		JPanel buttonPanel = new JPanel(new GridBagLayout());
-		gui.map.add(buttonPanel, GBC.eol().fill(GBC.HORIZONTAL));
-		buttonPanel.add(Box.createHorizontalGlue(), GBC.std().fill(GBC.HORIZONTAL));
-		buttonPanel.add(addAnno, GBC.std().insets(0,5,0,0));
-		buttonPanel.add(editAnno, GBC.std().insets(5,5,5,0));
-		buttonPanel.add(deleteAnno, GBC.std().insets(0,5,0,0));
-	}
-
-	public void ok() {
-		if (annotationSources.getModel().getSize() > 0) {
-			StringBuilder sb = new StringBuilder();
-			for (int i = 0; i < annotationSources.getModel().getSize(); ++i)
-				sb.append(";"+annotationSources.getModel().getElementAt(i));
-			Main.pref.put("annotation.sources", sb.toString().substring(1));
-		} else
-			Main.pref.put("annotation.sources", null);
-	}
-
-	/** 
-	 * Initialize the annotation presets (load and may display error)
-	 */
-	public static void initialize() {
-		annotationPresets = AnnotationPreset.readFromPreferences();
-	}
-}
Index: /src/org/openstreetmap/josm/gui/preferences/PluginPreference.java
===================================================================
--- /src/org/openstreetmap/josm/gui/preferences/PluginPreference.java	(revision 293)
+++ /src/org/openstreetmap/josm/gui/preferences/PluginPreference.java	(revision 294)
@@ -169,5 +169,5 @@
 						proxy.info.name, 
 						proxy.info.description, 
-						PluginInformation.getURLString(proxy.info.file.getPath())));
+						proxy.info.file == null ? null : PluginInformation.getURLString(proxy.info.file.getPath())));
 	    return availablePlugins.values();
     }
Index: /src/org/openstreetmap/josm/gui/preferences/PreferenceDialog.java
===================================================================
--- /src/org/openstreetmap/josm/gui/preferences/PreferenceDialog.java	(revision 293)
+++ /src/org/openstreetmap/josm/gui/preferences/PreferenceDialog.java	(revision 294)
@@ -103,5 +103,5 @@
 		settings.add(new CsvPreference());
 		settings.add(new ProjectionPreference());
-		settings.add(new AnnotationPresetPreference());
+		settings.add(new TaggingPresetPreference());
 		settings.add(new PluginPreference());
 		settings.add(Main.toolbar);
Index: /src/org/openstreetmap/josm/gui/preferences/TaggingPresetPreference.java
===================================================================
--- /src/org/openstreetmap/josm/gui/preferences/TaggingPresetPreference.java	(revision 294)
+++ /src/org/openstreetmap/josm/gui/preferences/TaggingPresetPreference.java	(revision 294)
@@ -0,0 +1,105 @@
+package org.openstreetmap.josm.gui.preferences;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.GridBagLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.util.Collection;
+import java.util.StringTokenizer;
+
+import javax.swing.Box;
+import javax.swing.DefaultListModel;
+import javax.swing.JButton;
+import javax.swing.JLabel;
+import javax.swing.JList;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.gui.tagging.TaggingPreset;
+import org.openstreetmap.josm.tools.GBC;
+
+public class TaggingPresetPreference implements PreferenceSetting {
+
+	public static Collection<TaggingPreset> taggingPresets;
+	private JList taggingPresetSources;
+
+	public void addGui(final PreferenceDialog gui) {
+		taggingPresetSources = new JList(new DefaultListModel());
+		String annos = Main.pref.get("taggingpreset.sources");
+		StringTokenizer st = new StringTokenizer(annos, ";");
+		while (st.hasMoreTokens())
+			((DefaultListModel)taggingPresetSources.getModel()).addElement(st.nextToken());
+
+		JButton addAnno = new JButton(tr("Add"));
+		addAnno.addActionListener(new ActionListener(){
+			public void actionPerformed(ActionEvent e) {
+				String source = JOptionPane.showInputDialog(Main.parent, tr("Tagging preset source"));
+				if (source == null)
+					return;
+				((DefaultListModel)taggingPresetSources.getModel()).addElement(source);
+				gui.requiresRestart = true;
+			}
+		});
+
+		JButton editAnno = new JButton(tr("Edit"));
+		editAnno.addActionListener(new ActionListener(){
+			public void actionPerformed(ActionEvent e) {
+				if (taggingPresetSources.getSelectedIndex() == -1)
+					JOptionPane.showMessageDialog(Main.parent, tr("Please select the row to edit."));
+				else {
+					String source = JOptionPane.showInputDialog(Main.parent, tr("Tagging preset source"), taggingPresetSources.getSelectedValue());
+					if (source == null)
+						return;
+					((DefaultListModel)taggingPresetSources.getModel()).setElementAt(source, taggingPresetSources.getSelectedIndex());
+					gui.requiresRestart = true;
+				}
+			}
+		});
+
+		JButton deleteAnno = new JButton(tr("Delete"));
+		deleteAnno.addActionListener(new ActionListener(){
+			public void actionPerformed(ActionEvent e) {
+				if (taggingPresetSources.getSelectedIndex() == -1)
+					JOptionPane.showMessageDialog(Main.parent, tr("Please select the row to delete."));
+				else {
+					((DefaultListModel)taggingPresetSources.getModel()).remove(taggingPresetSources.getSelectedIndex());
+					gui.requiresRestart = true;
+				}
+			}
+		});
+		taggingPresetSources.setVisibleRowCount(3);
+
+		taggingPresetSources.setToolTipText(tr("The sources (url or filename) of tagging preset definition files. See http://josm.eigenheimstrasse.de/wiki/TaggingPresets for help."));
+		addAnno.setToolTipText(tr("Add a new tagging preset source to the list."));
+		deleteAnno.setToolTipText(tr("Delete the selected source from the list."));
+
+		gui.map.add(new JLabel(tr("Tagging preset sources")), GBC.eol().insets(0,5,0,0));
+		gui.map.add(new JScrollPane(taggingPresetSources), GBC.eol().fill(GBC.BOTH));
+		JPanel buttonPanel = new JPanel(new GridBagLayout());
+		gui.map.add(buttonPanel, GBC.eol().fill(GBC.HORIZONTAL));
+		buttonPanel.add(Box.createHorizontalGlue(), GBC.std().fill(GBC.HORIZONTAL));
+		buttonPanel.add(addAnno, GBC.std().insets(0,5,0,0));
+		buttonPanel.add(editAnno, GBC.std().insets(5,5,5,0));
+		buttonPanel.add(deleteAnno, GBC.std().insets(0,5,0,0));
+	}
+
+	public void ok() {
+		if (taggingPresetSources.getModel().getSize() > 0) {
+			StringBuilder sb = new StringBuilder();
+			for (int i = 0; i < taggingPresetSources.getModel().getSize(); ++i)
+				sb.append(";"+taggingPresetSources.getModel().getElementAt(i));
+			Main.pref.put("taggingpreset.sources", sb.toString().substring(1));
+		} else
+			Main.pref.put("taggingpreset.sources", null);
+	}
+
+	/** 
+	 * Initialize the tagging presets (load and may display error)
+	 */
+	public static void initialize() {
+		taggingPresets = TaggingPreset.readFromPreferences();
+	}
+}
Index: /src/org/openstreetmap/josm/gui/tagging/ForwardActionListener.java
===================================================================
--- /src/org/openstreetmap/josm/gui/tagging/ForwardActionListener.java	(revision 294)
+++ /src/org/openstreetmap/josm/gui/tagging/ForwardActionListener.java	(revision 294)
@@ -0,0 +1,28 @@
+package org.openstreetmap.josm.gui.tagging;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+
+import org.openstreetmap.josm.gui.dialogs.PropertiesDialog;
+
+/**
+ * Just an ActionListener that forwards calls to actionPerformed to some other
+ * listener doing some refresh stuff on the way.
+ * @author imi
+ */
+public final class ForwardActionListener implements ActionListener {
+	public final TaggingPreset preset;
+
+	private final PropertiesDialog propertiesDialog;
+
+	public ForwardActionListener(PropertiesDialog propertiesDialog, TaggingPreset preset) {
+		this.propertiesDialog = propertiesDialog;
+		this.preset = preset;
+	}
+
+	public void actionPerformed(ActionEvent e) {
+		this.propertiesDialog.taggingPresets.setSelectedIndex(0);
+		e.setSource(this);
+		preset.actionPerformed(e);
+	}
+}
Index: /src/org/openstreetmap/josm/gui/tagging/TaggingCellRenderer.java
===================================================================
--- /src/org/openstreetmap/josm/gui/tagging/TaggingCellRenderer.java	(revision 294)
+++ /src/org/openstreetmap/josm/gui/tagging/TaggingCellRenderer.java	(revision 294)
@@ -0,0 +1,45 @@
+package org.openstreetmap.josm.gui.tagging;
+
+import java.awt.Component;
+import java.awt.Image;
+
+import javax.swing.Action;
+import javax.swing.DefaultListCellRenderer;
+import javax.swing.ImageIcon;
+import javax.swing.JComponent;
+import javax.swing.JLabel;
+import javax.swing.JList;
+
+import org.openstreetmap.josm.tools.ImageProvider;
+
+final public class TaggingCellRenderer extends DefaultListCellRenderer {
+	@Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+		TaggingPreset a = null;
+		if (value instanceof ForwardActionListener)
+			a = ((ForwardActionListener)value).preset;
+		else if (value instanceof TaggingPreset)
+			a = (TaggingPreset)value;
+		String name = a == null ? null : (String)a.getValue(Action.NAME);
+		if (name == null)
+			return super.getListCellRendererComponent(list, "", index, false, false);
+		JComponent c = (JComponent)super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
+		JLabel l = new JLabel(name);
+		l.setForeground(c.getForeground());
+		l.setBackground(c.getBackground());
+		l.setFont(c.getFont());
+		l.setBorder(c.getBorder());
+		ImageIcon icon = (ImageIcon)a.getValue(Action.SMALL_ICON);
+		if (icon != null)
+			l.setIcon(new ImageIcon(icon.getImage().getScaledInstance(16, 16, Image.SCALE_SMOOTH)));
+		else {
+			if (a.types == null)
+				l.setIcon(ImageProvider.get("data", "empty"));
+			else if (a.types.size() != 1)
+				l.setIcon(ImageProvider.get("data", "object"));
+			else
+				l.setIcon(ImageProvider.get("data", a.types.iterator().next().getSimpleName().toLowerCase()));
+		}
+		l.setOpaque(true);
+		return l;
+	}
+}
Index: /src/org/openstreetmap/josm/gui/tagging/TaggingPreset.java
===================================================================
--- /src/org/openstreetmap/josm/gui/tagging/TaggingPreset.java	(revision 294)
+++ /src/org/openstreetmap/josm/gui/tagging/TaggingPreset.java	(revision 294)
@@ -0,0 +1,309 @@
+package org.openstreetmap.josm.gui.tagging;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+import static org.openstreetmap.josm.tools.I18n.trn;
+
+import java.awt.GridBagLayout;
+import java.awt.Image;
+import java.awt.event.ActionEvent;
+import java.io.BufferedReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.UnsupportedEncodingException;
+import java.net.URL;
+import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.StringTokenizer;
+
+import javax.swing.AbstractAction;
+import javax.swing.Action;
+import javax.swing.ImageIcon;
+import javax.swing.JCheckBox;
+import javax.swing.JComboBox;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.command.ChangePropertyCommand;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.command.SequenceCommand;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+import org.openstreetmap.josm.tools.GBC;
+import org.openstreetmap.josm.tools.ImageProvider;
+import org.openstreetmap.josm.tools.XmlObjectParser;
+import org.xml.sax.SAXException;
+
+
+/**
+ * This class read encapsulate one tagging preset. A class method can
+ * read in all predefined presets, either shipped with JOSM or that are
+ * in the config directory.
+ * 
+ * It is also able to construct dialogs out of preset definitions.
+ */
+public class TaggingPreset extends AbstractAction {
+
+	public static abstract class Item {
+		public boolean focus = false;
+		abstract void addToPanel(JPanel p);
+		abstract void addCommands(Collection<OsmPrimitive> sel, List<Command> cmds);
+		boolean requestFocusInWindow() {return false;}
+	}
+
+	public static class Text extends Item {
+		public String key;
+		public String text;
+		public String default_;
+		public boolean delete_if_empty = false;
+
+		private JTextField value = new JTextField();
+
+		@Override public void addToPanel(JPanel p) {
+			value.setText(default_ == null ? "" : default_);
+			p.add(new JLabel(text), GBC.std().insets(0,0,10,0));
+			p.add(value, GBC.eol().fill(GBC.HORIZONTAL));
+		}
+		@Override public void addCommands(Collection<OsmPrimitive> sel, List<Command> cmds) {
+			String v = value.getText();
+			if (delete_if_empty && v.length() == 0)
+				v = null;
+			cmds.add(new ChangePropertyCommand(sel, key, v));
+		}
+		@Override boolean requestFocusInWindow() {return value.requestFocusInWindow();}
+	}
+
+	public static class Check extends Item {
+		public String key;
+		public String text;
+		public boolean default_ = false;
+
+		private JCheckBox check = new JCheckBox();
+
+		@Override public void addToPanel(JPanel p) {
+			check.setSelected(default_);
+			check.setText(text);
+			p.add(check, GBC.eol().fill(GBC.HORIZONTAL));
+		}
+		@Override public void addCommands(Collection<OsmPrimitive> sel, List<Command> cmds) {
+			cmds.add(new ChangePropertyCommand(sel, key, check.isSelected() ? "true" : null));
+		}
+		@Override boolean requestFocusInWindow() {return check.requestFocusInWindow();}
+	}
+
+	public static class Combo extends Item {
+		public String key;
+		public String text;
+		public String values;
+		public String display_values;
+		public String default_;
+		public boolean delete_if_empty = false;
+		public boolean editable = true;
+
+		private JComboBox combo;
+
+		@Override public void addToPanel(JPanel p) {
+			combo = new JComboBox((display_values != null ? display_values : values).split(","));
+			combo.setEditable(editable);
+			combo.setSelectedItem(default_);
+			p.add(new JLabel(text), GBC.std().insets(0,0,10,0));
+			p.add(combo, GBC.eol().fill(GBC.HORIZONTAL));
+		}
+		@Override public void addCommands(Collection<OsmPrimitive> sel, List<Command> cmds) {
+			String v = combo.getSelectedIndex() == -1 ? null : values.split(",")[combo.getSelectedIndex()];
+			String str = combo.isEditable()?combo.getEditor().getItem().toString() : v;
+			if (delete_if_empty && str != null && str.length() == 0)
+				str = null;
+			cmds.add(new ChangePropertyCommand(sel, key, str));
+		}
+		@Override boolean requestFocusInWindow() {return combo.requestFocusInWindow();}
+	}
+
+	public static class Label extends Item {
+		public String text;
+
+		@Override public void addToPanel(JPanel p) {
+			p.add(new JLabel(text), GBC.eol());
+		}
+		@Override public void addCommands(Collection<OsmPrimitive> sel, List<Command> cmds) {}
+	}
+
+	public static class Key extends Item {
+		public String key;
+		public String value;
+
+		@Override public void addToPanel(JPanel p) {}
+		@Override public void addCommands(Collection<OsmPrimitive> sel, List<Command> cmds) {
+			cmds.add(new ChangePropertyCommand(sel, key, value != null && !value.equals("") ? value : null));
+		}
+	}
+
+	/**
+	 * The types as preparsed collection.
+	 */
+	public Collection<Class<?>> types;
+	private List<Item> data = new LinkedList<Item>();
+
+	/**
+	 * Create an empty tagging preset. This will not have any items and
+	 * will be an empty string as text. createPanel will return null.
+	 * Use this as default item for "do not select anything".
+	 */
+	public TaggingPreset() {}
+
+	/**
+	 * Called from the XML parser to set the name of the tagging preset
+	 */
+	public void setName(String name) {
+		putValue(Action.NAME, name);
+		putValue("toolbar", "tagging_"+name);
+	}
+
+	/**
+	 * Called from the XML parser to set the icon
+	 */
+	public void setIcon(String iconName) {
+		ImageIcon icon = ImageProvider.getIfAvailable(null, iconName);
+		if (icon == null)
+			icon = new ImageIcon(iconName);
+		if (Math.max(icon.getIconHeight(), icon.getIconWidth()) != 24)
+			icon = new ImageIcon(icon.getImage().getScaledInstance(24, 24, Image.SCALE_SMOOTH));
+		putValue(Action.SMALL_ICON, icon);
+	}
+
+	/**
+	 * Called from the XML parser to set the types, this preset affects
+	 */
+	public void setType(String types) throws SAXException {
+		try {
+			for (String type : types.split(",")) {
+				type = Character.toUpperCase(type.charAt(0))+type.substring(1);
+				if (this.types == null)
+					this.types = new LinkedList<Class<?>>();
+				this.types.add(Class.forName("org.openstreetmap.josm.data.osm."+type));
+			}
+		} catch (ClassNotFoundException e) {
+			e.printStackTrace();
+			throw new SAXException(tr("Unknown type"));
+		}
+	}
+
+	public static List<TaggingPreset> readAll(InputStream inStream) throws SAXException {
+		BufferedReader in = null;
+		try {
+			in = new BufferedReader(new InputStreamReader(inStream, "UTF-8"));
+		} catch (UnsupportedEncodingException e) {
+			e.printStackTrace();
+			in = new BufferedReader(new InputStreamReader(inStream));
+		}
+		XmlObjectParser parser = new XmlObjectParser();
+		parser.mapOnStart("item", TaggingPreset.class);
+		parser.map("text", Text.class);
+		parser.map("check", Check.class);
+		parser.map("combo", Combo.class);
+		parser.map("label", Label.class);
+		parser.map("key", Key.class);
+		LinkedList<TaggingPreset> all = new LinkedList<TaggingPreset>();
+		parser.start(in);
+		while(parser.hasNext()) {
+			Object o = parser.next();
+			if (o instanceof TaggingPreset) {
+				all.add((TaggingPreset)o);
+				Main.toolbar.register((TaggingPreset)o);
+			} else
+				all.getLast().data.add((Item)o);
+		}
+		return all;
+	}
+
+	public static Collection<TaggingPreset> readFromPreferences() {
+		LinkedList<TaggingPreset> allPresets = new LinkedList<TaggingPreset>();
+		String allTaggingPresets = Main.pref.get("taggingpreset.sources");
+		StringTokenizer st = new StringTokenizer(allTaggingPresets, ";");
+		while (st.hasMoreTokens()) {
+			InputStream in = null;
+			String source = st.nextToken();
+			try {
+				if (source.startsWith("http") || source.startsWith("ftp") || source.startsWith("file"))
+					in = new URL(source).openStream();
+				else if (source.startsWith("resource://"))
+					in = Main.class.getResourceAsStream(source.substring("resource:/".length()));
+				else
+					in = new FileInputStream(source);
+				allPresets.addAll(TaggingPreset.readAll(in));
+				in.close();
+			} catch (IOException e) {
+				e.printStackTrace();
+				JOptionPane.showMessageDialog(Main.parent, tr("Could not read tagging preset source: {0}",source));
+			} catch (SAXException e) {
+				e.printStackTrace();
+				JOptionPane.showMessageDialog(Main.parent, tr("Error parsing {0}: ", source)+e.getMessage());
+			}
+		}
+		return allPresets;
+	}
+
+
+	public JPanel createPanel() {
+		if (data == null)
+			return null;
+		JPanel p = new JPanel(new GridBagLayout());
+		for (Item i : data)
+			i.addToPanel(p);
+		return p;
+	}
+
+	public void actionPerformed(ActionEvent e) {
+		Collection<OsmPrimitive> sel = Main.ds.getSelected();
+		JPanel p = createPanel();
+		if (p == null)
+			return;
+		int answer = JOptionPane.OK_OPTION;
+		if (p.getComponentCount() != 0) {
+			final JOptionPane optionPane = new JOptionPane(p, JOptionPane.PLAIN_MESSAGE, JOptionPane.OK_CANCEL_OPTION){
+				@Override public void selectInitialValue() {
+					for (Item i : data) {
+						if (i.focus) {
+							System.out.println(i.requestFocusInWindow());
+							return;
+						}
+					}
+				}
+			};
+			optionPane.createDialog(Main.parent, trn("Change {0} object", "Change {0} objects", sel.size(), sel.size())).setVisible(true);
+			Object answerObj = optionPane.getValue();
+			if (answerObj == null || answerObj == JOptionPane.UNINITIALIZED_VALUE ||
+					(answerObj instanceof Integer && (Integer)answerObj != JOptionPane.OK_OPTION))
+				answer = JOptionPane.CANCEL_OPTION;
+		}
+		if (answer == JOptionPane.OK_OPTION) {
+			Command cmd = createCommand(Main.ds.getSelected());
+			if (cmd != null)
+				Main.main.editLayer().add(cmd);
+		}
+		Main.ds.setSelected(Main.ds.getSelected()); // force update
+	}
+
+	private Command createCommand(Collection<OsmPrimitive> participants) {
+		Collection<OsmPrimitive> sel = new LinkedList<OsmPrimitive>();
+		for (OsmPrimitive osm : participants)
+			if (types == null || types.contains(osm.getClass()))
+				sel.add(osm);
+		if (sel.isEmpty())
+			return null;
+
+		List<Command> cmds = new LinkedList<Command>();
+		for (Item i : data)
+			i.addCommands(sel, cmds);
+		if (cmds.size() == 0)
+			return null;
+		else if (cmds.size() == 1)
+			return cmds.get(0);
+		else
+			return new SequenceCommand(tr("Change Properties"), cmds);
+	}
+}
Index: /test/unit/org/openstreetmap/josm/gui/tagging/TaggingPresetTest.java
===================================================================
--- /test/unit/org/openstreetmap/josm/gui/tagging/TaggingPresetTest.java	(revision 294)
+++ /test/unit/org/openstreetmap/josm/gui/tagging/TaggingPresetTest.java	(revision 294)
@@ -0,0 +1,72 @@
+package org.openstreetmap.josm.gui.tagging;
+
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.util.List;
+
+import javax.swing.Action;
+import javax.swing.Icon;
+
+import junit.framework.TestCase;
+
+import org.openstreetmap.josm.gui.tagging.TaggingPreset;
+import org.openstreetmap.josm.gui.tagging.TaggingPreset.Check;
+import org.openstreetmap.josm.gui.tagging.TaggingPreset.Combo;
+import org.openstreetmap.josm.gui.tagging.TaggingPreset.Key;
+import org.openstreetmap.josm.gui.tagging.TaggingPreset.Label;
+import org.openstreetmap.josm.gui.tagging.TaggingPreset.Text;
+
+public class TaggingPresetTest extends TestCase {
+
+	public void testTaggingPresetLoads() throws Exception {
+		InputStream in = getClass().getResourceAsStream("taggingpreset-test.xml");
+		List<TaggingPreset> all = TaggingPreset.readAll(in);
+
+		assertEquals(1, all.size());
+		TaggingPreset a = all.get(0);
+		assertEquals("Highway", a.getValue(Action.NAME));
+		Field dataField = a.getClass().getDeclaredField("data");
+		dataField.setAccessible(true);
+		List<?> data = (List<?>)dataField.get(a);
+		assertEquals(5, data.size());
+
+		Label label = (Label)data.get(0);
+		assertEquals("Inserting a highway in UK", label.text);
+
+		Text text = (Text)data.get(1);
+		assertEquals("name", text.key);
+		assertEquals("Highway (e.g. M3)", text.text);
+		assertFalse(text.delete_if_empty);
+		assertNull(text.default_);
+
+		Combo combo = (Combo)data.get(2);
+		assertEquals("highway", combo.key);
+		assertEquals("Type", combo.text);
+		assertEquals("major,minor", combo.values);
+		assertTrue(combo.delete_if_empty);
+		assertTrue(combo.editable);
+		assertNull(combo.default_);
+
+		Check check = (Check)data.get(3);
+		assertEquals("oneway", check.key);
+		assertEquals("Oneway", check.text);
+		assertTrue(check.default_);
+
+		Key key = (Key)data.get(4);
+		assertEquals("class", key.key);
+		assertEquals("highway", key.value);
+	}
+	
+	public void testIconLoadsFromClasspath() throws Exception {
+		String xml = "<annotations><item icon='logo'></item></annotations>";
+		List<TaggingPreset> all = TaggingPreset.readAll(new ByteArrayInputStream(xml.getBytes()));
+
+		assertEquals(1, all.size());
+
+		Icon icon = (Icon)all.get(0).getValue(Action.SMALL_ICON);
+		assertNotNull(icon);
+		assertEquals("Icon loaded and of correct size", 
+				24, Math.max(icon.getIconHeight(), icon.getIconWidth()));
+    }
+}
Index: /test/unit/org/openstreetmap/josm/gui/tagging/taggingpreset-test.xml
===================================================================
--- /test/unit/org/openstreetmap/josm/gui/tagging/taggingpreset-test.xml	(revision 294)
+++ /test/unit/org/openstreetmap/josm/gui/tagging/taggingpreset-test.xml	(revision 294)
@@ -0,0 +1,14 @@
+<annotations>
+  <item name="Highway">
+    <label text="Inserting a highway in UK" />
+
+    <text key="name" text="Highway (e.g. M3)" />
+    <combo key="highway" text="Type" values="major,minor" delete_if_empty="true" />
+
+    <!-- Highways are usually oneway -->
+    <check key="oneway" text="Oneway" default="on" />
+
+    <!-- Always setting class=highway -->
+    <key key="class" value="highway" />
+  </item>
+</annotations>
