Index: src/org/openstreetmap/josm/gui/annotation/AnnotationCellRenderer.java
===================================================================
--- src/org/openstreetmap/josm/gui/annotation/AnnotationCellRenderer.java	(revision 192)
+++ src/org/openstreetmap/josm/gui/annotation/AnnotationCellRenderer.java	(revision 193)
@@ -15,5 +15,9 @@
 final public class AnnotationCellRenderer extends DefaultListCellRenderer {
 	@Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
-		AnnotationPreset a = value == null ? null : ((ForwardActionListener)value).preset;
+		AnnotationPreset a = null;
+		if (value instanceof ForwardActionListener)
+			a = ((ForwardActionListener)value).preset;
+		else if (value instanceof AnnotationPreset)
+			a = (AnnotationPreset)value;
 		String name = a == null ? null : (String)a.getValue(Action.NAME);
 		if (name == null)
Index: src/org/openstreetmap/josm/gui/annotation/AnnotationPreset.java
===================================================================
--- src/org/openstreetmap/josm/gui/annotation/AnnotationPreset.java	(revision 192)
+++ src/org/openstreetmap/josm/gui/annotation/AnnotationPreset.java	(revision 193)
@@ -20,4 +20,5 @@
 
 import javax.swing.AbstractAction;
+import javax.swing.Action;
 import javax.swing.ImageIcon;
 import javax.swing.JCheckBox;
@@ -34,8 +35,6 @@
 import org.openstreetmap.josm.data.osm.OsmPrimitive;
 import org.openstreetmap.josm.tools.GBC;
-import org.xml.sax.Attributes;
+import org.openstreetmap.josm.tools.XmlObjectParser;
 import org.xml.sax.SAXException;
-
-import uk.co.wilson.xml.MinML2;
 
 
@@ -53,24 +52,21 @@
 		void addCommands(Collection<OsmPrimitive> sel, List<Command> cmds);
 	}
-
+	
 	public static class Text implements Item {
-		private String key;
-		private String label;
+		public String key;
+		public String text;
+		public String default_;
+		public boolean delete_if_empty = false;
+
 		private JTextField value = new JTextField();
-		private boolean deleteIfEmpty;
-
-		public void addToPanel(JPanel p) {
-			p.add(new JLabel(label), GBC.std().insets(0,0,10,0));
+
+		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));
 		}
-		public Text(String key, String label, String value, boolean deleteIfEmpty) {
-			this.key = key;
-			this.label = label;
-			this.value.setText(value == null ? "" : value);
-			this.deleteIfEmpty = deleteIfEmpty;
-		}
 		public void addCommands(Collection<OsmPrimitive> sel, List<Command> cmds) {
 			String v = value.getText();
-			if (deleteIfEmpty && v.length() == 0)
+			if (delete_if_empty && v.length() == 0)
 				v = null;
 			cmds.add(new ChangePropertyCommand(sel, key, v));
@@ -79,15 +75,15 @@
 
 	public static class Check implements Item {
-		private String key;
+		public String key;
+		public String text;
+		public boolean default_ = false;
+		
 		private JCheckBox check = new JCheckBox();
 
 		public void addToPanel(JPanel p) {
+			check.setSelected(default_);
+			check.setText(text);
 			p.add(check, GBC.eol().fill(GBC.HORIZONTAL));
 		}
-		public Check(String key, String label, boolean check) {
-			this.key = key;
-			this.check.setText(label);
-			this.check.setSelected(check);
-		}
 		public void addCommands(Collection<OsmPrimitive> sel, List<Command> cmds) {
 			cmds.add(new ChangePropertyCommand(sel, key, check.isSelected() ? "true" : null));
@@ -96,27 +92,25 @@
 
 	public static class Combo implements Item {
-		private String key;
-		private String label;
+		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;
-		private final String[] values;
-		private boolean deleteIfEmpty;
-
-		public void addToPanel(JPanel p) {
-			p.add(new JLabel(label), GBC.std().insets(0,0,10,0));
+
+		public void addToPanel(JPanel p) {
+			combo = new JComboBox(display_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));
 		}
-		public Combo(String key, String label, String def, String[] values, String[] displayedValues, boolean editable, boolean deleteIfEmpty) {
-			this.key = key;
-			this.label = label;
-			this.values = values;
-			this.deleteIfEmpty = deleteIfEmpty;
-			combo = new JComboBox(displayedValues);
-			combo.setEditable(editable);
-			combo.setSelectedItem(def);
-		}
-		public void addCommands(Collection<OsmPrimitive> sel, List<Command> cmds) {
-			String v = combo.getSelectedIndex() == -1 ? null : values[combo.getSelectedIndex()];
+		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 (deleteIfEmpty && str != null && str.length() == 0)
+			if (delete_if_empty && str != null && str.length() == 0)
 				str = null;
 			cmds.add(new ChangePropertyCommand(sel, key, str));
@@ -125,24 +119,17 @@
 
 	public static class Label implements Item {
-		private String text;
+		public String text;
 
 		public void addToPanel(JPanel p) {
 			p.add(new JLabel(text), GBC.eol());
 		}
-		public Label(String text) {
-			this.text = text;
-		}
 		public void addCommands(Collection<OsmPrimitive> sel, List<Command> cmds) {}
 	}
 
 	public static class Key implements Item {
-		private String key;
-		private String value;
+		public String key;
+		public String value;
 
 		public void addToPanel(JPanel p) {}
-		public Key(String key, String value) {
-			this.key = key;
-			this.value = value;
-		}
 		public void addCommands(Collection<OsmPrimitive> sel, List<Command> cmds) {
 			cmds.add(new ChangePropertyCommand(sel, key, value != null && !value.equals("") ? value : null));
@@ -150,93 +137,9 @@
 	}
 
-	private static class Parser extends MinML2 {
-		List<AnnotationPreset> data = new LinkedList<AnnotationPreset>();
-		List<Item> current;
-		String currentName;
-		Collection<Class<?>> currentTypes;
-		ImageIcon currentIcon;
-		private static int unknownCounter = 1;
-
-		@Override public void startElement(String ns, String lname, String qname, Attributes a) throws SAXException {
-			if (qname.equals("annotations"))
-				return;
-			if (qname.equals("item")) {
-				current = new LinkedList<Item>();
-				currentName = a.getValue("name");
-				if (currentName == null)
-					currentName = "Unnamed Preset #"+(unknownCounter++);
-				if (a.getValue("type") != null) {
-					String s = a.getValue("type");
-					try {
-						for (String type : s.split(",")) {
-							type = Character.toUpperCase(type.charAt(0))+type.substring(1);
-							if (currentTypes == null)
-								currentTypes = new LinkedList<Class<?>>();
-							currentTypes.add(Class.forName("org.openstreetmap.josm.data.osm."+type));
-						}
-					} catch (ClassNotFoundException e) {
-						e.printStackTrace();
-						throw new SAXException(tr("Unknown type at line {0}", getLineNumber()));
-					}
-				}
-				currentIcon = (a.getValue("icon") == null) ? null : new ImageIcon(a.getValue("icon"));
-			} else if (qname.equals("text"))
-				current.add(new Text(a.getValue("key"), a.getValue("text"), a.getValue("default"), parseBoolean(a.getValue("delete_if_empty"))));
-			else if (qname.equals("check")) {
-				boolean checked = parseBoolean(a.getValue("default"));
-				current.add(new Check(a.getValue("key"), a.getValue("text"), checked));
-			} else if (qname.equals("label"))
-				current.add(new Label(a.getValue("text")));
-			else if (qname.equals("combo")) {
-				String[] values = a.getValue("values").split(",");
-				String s = a.getValue("readonly");
-				String dvstr = a.getValue("display_values");
-				boolean editable = !parseBoolean(s);
-				if (dvstr != null) {
-					if (editable && s != null)
-						throw new SAXException(tr("Cannot have a writable combobox with default values (line {0})", getLineNumber()));
-					editable = false; // for combos with display_value readonly default to false
-				}
-				String[] displayValues = dvstr == null ? values : dvstr.split(",");
-				if (displayValues.length != values.length)
-					throw new SAXException(tr("display_values ({0}) and values ({1}) must be of same number of elements.",
-							displayValues.length+" "+trn("element", "elements", displayValues.length),
-							values.length+" "+trn("element", "elements", values.length)));
-				current.add(new Combo(a.getValue("key"), a.getValue("text"), a.getValue("default"), values, displayValues, editable, parseBoolean(a.getValue("delete_if_empty"))));
-			} else if (qname.equals("key"))
-				current.add(new Key(a.getValue("key"), a.getValue("value")));
-			else
-				throw new SAXException(tr("Unknown annotation object {0} at line {1} column {2}", qname, getLineNumber(), getColumnNumber()));
-		}
-
-		private boolean parseBoolean(String s) {
-			return s != null && 
-				!s.equals("0") && 
-				!s.startsWith("off") && 
-				!s.startsWith("false") &&
-				!s.startsWith("no");
-		}
-
-		@Override public void endElement(String ns, String lname, String qname) {
-			if (qname.equals("item")) {
-				data.add(new AnnotationPreset(current, currentName, currentIcon, currentTypes));
-				current = null;
-				currentName = null;
-				currentTypes = null;
-				currentIcon = null;
-			}
-		}
-	}
-
-	private List<Item> data;
-	public Collection<Class<?>> types;
-	
-	public AnnotationPreset(List<Item> data, String name, ImageIcon icon, Collection<Class<?>> currentTypes) {
-		super(name, icon == null ? null : new ImageIcon(icon.getImage().getScaledInstance(24, 24, Image.SCALE_SMOOTH)));
-		putValue("toolbar", "annotation_"+name);
-		this.data = data;
-		this.types = currentTypes;
-		Main.toolbar.register(this);
-	}
+	/**
+     * The types as preparsed collection.
+     */
+    public Collection<Class<?>> types;
+	private List<Item> data = new LinkedList<Item>();
 
 	/**
@@ -247,5 +150,37 @@
 	public AnnotationPreset() {}
 
-	public static List<AnnotationPreset> readAll(InputStream inStream) throws IOException, SAXException {
+	/**
+	 * Called from the XML parser to set the name of the annotation preset
+	 */
+	public void setName(String name) {
+		putValue(Action.NAME, name);
+		putValue("toolbar", "annotation_"+name);
+	}
+
+	/**
+	 * Called from the XML parser to set the icon
+	 */
+	public void setIcon(String icon) {
+		putValue(Action.SMALL_ICON, new ImageIcon(new ImageIcon(icon).getImage().getScaledInstance(24, 24, Image.SCALE_SMOOTH)));
+	}
+	
+	/**
+	 * 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<AnnotationPreset> readAll(InputStream inStream) throws SAXException {
 		BufferedReader in = null;
 		try {
@@ -255,7 +190,22 @@
 			in = new BufferedReader(new InputStreamReader(inStream));
 		}
-		Parser p = new Parser();
-		p.parse(in);
-		return p.data;
+		XmlObjectParser parser = new XmlObjectParser();
+		parser.mapOnStart("item", AnnotationPreset.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<AnnotationPreset> all = new LinkedList<AnnotationPreset>();
+		parser.start(in);
+		while(parser.hasNext()) {
+			Object o = parser.next();
+			if (o instanceof AnnotationPreset) {
+				all.add((AnnotationPreset)o);
+				Main.toolbar.register((AnnotationPreset)o);
+			} else
+				all.getLast().data.add((Item)o);
+		}
+		return all;
 	}
 
@@ -287,5 +237,5 @@
 	}
 
-	
+
 	public JPanel createPanel() {
 		if (data == null)
Index: src/org/openstreetmap/josm/tools/XmlObjectParser.java
===================================================================
--- src/org/openstreetmap/josm/tools/XmlObjectParser.java	(revision 193)
+++ src/org/openstreetmap/josm/tools/XmlObjectParser.java	(revision 193)
@@ -0,0 +1,247 @@
+package org.openstreetmap.josm.tools;
+
+import java.io.Reader;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Stack;
+import java.util.concurrent.ArrayBlockingQueue;
+import java.util.concurrent.BlockingQueue;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.SAXException;
+
+import uk.co.wilson.xml.MinML2;
+
+/**
+ * An helper class that reads from a XML stream into specific objects.
+ *
+ * @author Imi
+ */
+public class XmlObjectParser implements Iterable<Object> {
+
+	public static class Uniform<T> implements Iterable<T>{
+		private Iterator<Object> iterator;
+		/**
+		 * @param klass This has to be specified since generics are ereased from
+		 * class files so the JVM cannot deduce T itself.
+		 */
+		public Uniform(Reader input, String tagname, Class<T> klass) {
+			XmlObjectParser parser = new XmlObjectParser();
+			parser.map(tagname, klass);
+			parser.start(input);
+			iterator = parser.iterator();
+		}
+		public Iterator<T> iterator() {
+			return new Iterator<T>(){
+				public boolean hasNext() {return iterator.hasNext();}
+				@SuppressWarnings("unchecked") public T next() {return (T)iterator.next();}
+				public void remove() {iterator.remove();}
+			};
+		}
+	}
+
+	private class Parser extends MinML2 {
+		Stack<Object> current = new Stack<Object>();
+		String characters = "";
+		@Override public void startElement(String ns, String lname, String qname, Attributes a) throws SAXException {
+			if (mapping.containsKey(qname)) {
+				Class<?> klass = mapping.get(qname).klass;
+				try {
+					current.push(klass.newInstance());
+				} catch (Exception e) {
+					throw new SAXException(e);
+				}
+				for (int i = 0; i < a.getLength(); ++i)
+					setValue(a.getQName(i), a.getValue(i));
+				if (mapping.get(qname).onStart)
+					report();
+			}
+		}
+		@Override public void endElement(String ns, String lname, String qname) throws SAXException {
+			if (mapping.containsKey(qname) && !mapping.get(qname).onStart)
+				report();
+			else if (characters != null && !current.isEmpty())
+				setValue(qname, characters);
+		}
+		@Override public void characters(char[] ch, int start, int length) {
+			String s = new String(ch, start, length);
+			characters += s;
+		}
+
+		private void report() {
+			try {
+				queue.put(current.pop());
+			} catch (InterruptedException e) {
+			}
+			characters = "";
+		}
+
+		private Object getValueForClass(Class<?> klass, String value) {
+			if (klass == Boolean.TYPE)
+				return parseBoolean(value);
+			else if (klass == Integer.TYPE || klass == Long.TYPE)
+				return Long.parseLong(value);
+			else if (klass == Float.TYPE || klass == Double.TYPE)
+				return Double.parseDouble(value);
+			return value;
+		}
+		
+		private void setValue(String fieldName, String value) throws SAXException {
+			if (fieldName.equals("class") || fieldName.equals("default") || fieldName.equals("throw") || fieldName.equals("new") || fieldName.equals("null"))
+				fieldName += "_";
+			try {
+				Object c = current.peek();
+				Field f = null;
+				try {
+	                f = c.getClass().getField(fieldName);
+                } catch (NoSuchFieldException e) {
+                }
+				if (f != null && Modifier.isPublic(f.getModifiers()))
+					f.set(c, getValueForClass(f.getType(), value));
+				else {
+					fieldName = "set" + fieldName.substring(0,1).toUpperCase() + fieldName.substring(1);
+					Method[] methods = c.getClass().getDeclaredMethods();
+					for (Method m : methods) {
+						if (m.getName().equals(fieldName) && m.getParameterTypes().length == 1) {
+							m.invoke(c, new Object[]{getValueForClass(m.getParameterTypes()[0], value)});
+							return;
+						}
+					}
+				}
+			} catch (Exception e) {
+				throw new SAXException(e);
+			}
+		}
+		private boolean parseBoolean(String s) {
+			return s != null && 
+				!s.equals("0") && 
+				!s.startsWith("off") && 
+				!s.startsWith("false") &&
+				!s.startsWith("no");
+		}
+	}
+
+	private static class Entry {
+		Class<?> klass;
+		boolean onStart;
+		public Entry(Class<?> klass, boolean onStart) {
+			super();
+			this.klass = klass;
+			this.onStart = onStart;
+		}
+	}
+
+	private Map<String, Entry> mapping = new HashMap<String, Entry>();
+	private Parser parser;
+	
+	/**
+	 * The queue of already parsed items from the parsing thread.
+	 */
+	private BlockingQueue<Object> queue = new ArrayBlockingQueue<Object>(10);
+
+	/**
+	 * This stores one item retrieved from the queue to give hasNext a chance.
+	 * So this is also the object that will be returned on the next call to next().
+	 */
+	private Object lookAhead = null;
+	
+	/**
+	 * This object represent the end of the stream (null is not allowed as
+	 * member in class Queue).
+	 */
+	private Object EOS = new Object();
+
+	public XmlObjectParser() {
+		parser = new Parser();
+	}
+
+	public Iterable<Object> start(final Reader in) {
+		new Thread(){
+			@Override public void run() {
+				try {
+					parser.parse(in);
+				} catch (Exception e) {
+					try {
+						queue.put(e);
+					} catch (InterruptedException e1) {
+					}
+				}
+				parser = null;
+				try {
+					queue.put(EOS);
+				} catch (InterruptedException e) {
+				}
+			}
+		}.start();
+		return this;
+	}
+
+	public void map(String tagName, Class<?> klass) {
+		mapping.put(tagName, new Entry(klass,false));
+	}
+
+	public void mapOnStart(String tagName, Class<?> klass) {
+		mapping.put(tagName, new Entry(klass,true));
+	}
+
+	/**
+	 * @return The next object from the xml stream or <code>null</code>,
+	 * if no more objects.
+	 */
+	public Object next() throws SAXException {
+		fillLookAhead();
+		if (lookAhead == EOS)
+			throw new NoSuchElementException();
+		Object o = lookAhead;
+		lookAhead = null;
+		return o;
+	}
+
+	private void fillLookAhead() throws SAXException {
+		if (lookAhead != null)
+			return;
+	    try {
+			lookAhead = queue.take();
+			if (lookAhead instanceof SAXException)
+				throw (SAXException)lookAhead;
+			else if (lookAhead instanceof RuntimeException)
+				throw (RuntimeException)lookAhead;
+			else if (lookAhead instanceof Exception)
+				throw new SAXException((Exception)lookAhead);
+		} catch (InterruptedException e) {
+        	throw new RuntimeException("XmlObjectParser must not be interrupted.", e);
+		}
+    }
+
+	public boolean hasNext() throws SAXException {
+		fillLookAhead();
+        return lookAhead != EOS;
+	}
+
+	public Iterator<Object> iterator() {
+		return new Iterator<Object>(){
+			public boolean hasNext() {
+				try {
+					return XmlObjectParser.this.hasNext();
+				} catch (SAXException e) {
+					throw new RuntimeException(e);
+				}
+			}
+			public Object next() {
+				try {
+					return XmlObjectParser.this.next();
+				} catch (SAXException e) {
+					throw new RuntimeException(e);
+				}
+			}
+			public void remove() {
+				throw new UnsupportedOperationException();
+			}
+		};
+	}
+}
