Index: src/org/openstreetmap/josm/actions/AlignInCircleAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/AlignInCircleAction.java	(revision 163)
+++ src/org/openstreetmap/josm/actions/AlignInCircleAction.java	(revision 167)
@@ -68,5 +68,4 @@
 
 		Main.main.editLayer().add(new SequenceCommand(tr("Align Nodes in Circle"), cmds));
-		Main.ds.setSelected(avn);
 		Main.map.repaint();
 	}
Index: src/org/openstreetmap/josm/actions/AlignInLineAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/AlignInLineAction.java	(revision 167)
+++ src/org/openstreetmap/josm/actions/AlignInLineAction.java	(revision 167)
@@ -0,0 +1,114 @@
+package org.openstreetmap.josm.actions;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.util.Collection;
+import java.util.LinkedList;
+
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.command.MoveCommand;
+import org.openstreetmap.josm.command.SequenceCommand;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+
+/**
+ * Aligns all selected nodes into a straight line (useful for
+ * roads that should be straight, but have side roads and
+ * therefore need multiple nodes)
+ * 
+ * @author Matthew Newton
+ */
+public final class AlignInLineAction extends JosmAction {
+
+	public AlignInLineAction() {
+		super(tr("Align Nodes in Line"), "alignline", tr("Move the selected nodes onto a line."), KeyEvent.VK_L, KeyEvent.CTRL_MASK | KeyEvent.SHIFT_MASK);
+	}
+
+	/**
+	 * The general algorithm here is to find the two selected nodes
+	 * that are furthest apart, and then to align all other selected
+	 * nodes onto the straight line between these nodes.
+	 */
+	public void actionPerformed(ActionEvent e) {
+		Collection<OsmPrimitive> sel = Main.ds.getSelected();
+		Collection<Node> nodes = new LinkedList<Node>();
+		Collection<Node> itnodes = new LinkedList<Node>();
+		for (OsmPrimitive osm : sel)
+			if (osm instanceof Node) {
+				nodes.add((Node)osm);
+				itnodes.add((Node)osm);
+			}
+		if (nodes.size() < 3) {
+			JOptionPane.showMessageDialog(Main.parent, tr("Please select at least three nodes."));
+			return;
+		}
+
+		// Find from the selected nodes two that are the furthest apart.
+		// Let's call them A and B.
+		double distance = 0;
+
+		Node nodea = null;
+		Node nodeb = null;
+
+		for (Node n : nodes) {
+			itnodes.remove(n);
+			for (Node m : itnodes) {
+				double dist = Math.sqrt(n.eastNorth.distance(m.eastNorth));
+				if (dist > distance) {
+					nodea = n;
+					nodeb = m;
+					distance = dist;
+				}
+			}
+		}
+
+		// Remove the nodes A and B from the list of nodes to move
+		nodes.remove(nodea);
+		nodes.remove(nodeb);
+
+		// Find out co-ords of A and B
+		double ax = nodea.eastNorth.east();
+		double ay = nodea.eastNorth.north();
+		double bx = nodeb.eastNorth.east();
+		double by = nodeb.eastNorth.north();
+
+		// A list of commands to do
+		Collection<Command> cmds = new LinkedList<Command>();
+
+		// OK, for each node to move, work out where to move it!
+		for (Node n : nodes) {
+			// Get existing co-ords of node to move
+			double nx = n.eastNorth.east();
+			double ny = n.eastNorth.north();
+
+			if (ax == bx) {
+				// Special case if AB is vertical...
+				nx = ax;
+			} else if (ay == by) {
+				// ...or horizontal
+				ny = ay;
+			} else {
+				// Otherwise calculate position by solving y=mx+c
+				double m1 = (by - ay) / (bx - ax);
+				double c1 = ay - (ax * m1);
+				double m2 = (-1) / m1;
+				double c2 = n.eastNorth.north() - (n.eastNorth.east() * m2);
+
+				nx = (c2 - c1) / (m1 - m2);
+				ny = (m1 * nx) + c1;
+			}
+
+			// Add the command to move the node to its new position.
+			cmds.add(new MoveCommand(n, nx - n.eastNorth.east(), ny - n.eastNorth.north() ));
+		}
+
+		// Do it!
+		Main.main.editLayer().add(new SequenceCommand(tr("Align Nodes in Line"), cmds));
+		Main.map.repaint();
+	}
+}
Index: src/org/openstreetmap/josm/actions/ExternalToolsAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/ExternalToolsAction.java	(revision 163)
+++ 	(revision )
@@ -1,356 +1,0 @@
-package org.openstreetmap.josm.actions;
-
-import static org.openstreetmap.josm.tools.I18n.tr;
-
-import java.awt.event.ActionEvent;
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-import java.io.PrintWriter;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.Stack;
-
-import javax.swing.AbstractAction;
-import javax.swing.JMenu;
-import javax.swing.JOptionPane;
-
-import org.openstreetmap.josm.Main;
-import org.openstreetmap.josm.command.AddCommand;
-import org.openstreetmap.josm.command.ChangeCommand;
-import org.openstreetmap.josm.command.Command;
-import org.openstreetmap.josm.command.DeleteCommand;
-import org.openstreetmap.josm.command.SequenceCommand;
-import org.openstreetmap.josm.data.Bounds;
-import org.openstreetmap.josm.data.coor.LatLon;
-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.Segment;
-import org.openstreetmap.josm.data.osm.Way;
-import org.openstreetmap.josm.data.osm.visitor.AddVisitor;
-import org.openstreetmap.josm.data.osm.visitor.AllNodesVisitor;
-import org.openstreetmap.josm.data.osm.visitor.CollectBackReferencesVisitor;
-import org.openstreetmap.josm.gui.PleaseWaitRunnable;
-import org.openstreetmap.josm.gui.layer.Layer;
-import org.openstreetmap.josm.gui.layer.RawGpsLayer;
-import org.openstreetmap.josm.gui.layer.RawGpsLayer.GpsPoint;
-import org.openstreetmap.josm.io.GpxWriter;
-import org.openstreetmap.josm.io.OsmReader;
-import org.openstreetmap.josm.io.OsmWriter;
-import org.xml.sax.Attributes;
-import org.xml.sax.SAXException;
-
-import uk.co.wilson.xml.MinML2;
-
-/**
- * Launches external tools configured in the preferences.
- *
- * @author Imi
- */
-public class ExternalToolsAction extends AbstractAction {
-
-	private final Collection<String> flags;
-	private final Collection<String> input;
-	private final String output;
-	private final String[] exec;
-
-	private final class ExecuteToolRunner extends PleaseWaitRunnable {
-		private final Process p;
-		private DataSet dataSet;
-		private DataSet fromDataSet;
-		private ExecuteToolRunner(String msg, Process p) {
-			super(msg);
-			this.p = p;
-		}
-
-		@Override protected void realRun() throws SAXException, IOException {
-			Main.pleaseWaitDlg.currentAction.setText(tr("Executing {0}",getValue(NAME)));
-			if (!input.isEmpty()) {
-				fromDataSet = new DataSet();
-				final Collection<GpsPoint> gpxPoints = new LinkedList<GpsPoint>();
-				final boolean addOsm = !flags.contains("noosm");
-				final boolean addGpx = flags.contains("gpx");
-
-				AddVisitor adder = new AddVisitor(fromDataSet);
-				if (flags.contains("include_references")) {
-					adder = new AddVisitor(fromDataSet){
-						@Override public void visit(Node n) {
-							if (!ds.nodes.contains(n))
-								super.visit(n);
-                        }
-						@Override public void visit(Segment s) {
-	                        super.visit(s);
-	                		if (!s.incomplete) {
-	                			if (!ds.nodes.contains(s.from))
-	                				s.from.visit(this);
-	                			if (!ds.nodes.contains(s.to))
-	                				s.to.visit(this);
-	                		}
-                        }
-						@Override public void visit(Way w) {
-	                        super.visit(w);
-	            			for (Segment s : w.segments)
-	            				if (!ds.segments.contains(s))
-	            					s.visit(this);
-                        }
-					};
-				}
-				if (input.contains("selection")) {
-					Collection<OsmPrimitive> sel = Main.ds.getSelected();
-					if (addOsm) {
-						for (OsmPrimitive osm : sel)
-							osm.visit(adder);
-						if (flags.contains("include_back_references")) {
-							CollectBackReferencesVisitor v = new CollectBackReferencesVisitor(Main.ds);
-							for (OsmPrimitive osm : sel)
-								osm.visit(v);
-							AddVisitor a = new AddVisitor(fromDataSet);
-							for (OsmPrimitive osm : v.data)
-								osm.visit(a);
-						}
-					}
-					if (addGpx) {
-						AllNodesVisitor v = new AllNodesVisitor();
-						for (OsmPrimitive osm : sel)
-							osm.visit(v);
-						Bounds b = new Bounds();
-						for (Node n : v.nodes)
-							b.extend(n.coor);
-						for (Layer l : Main.map.mapView.getAllLayers()) {
-							if (!(l instanceof RawGpsLayer))
-								continue;
-							RawGpsLayer layer = (RawGpsLayer)l;
-							for (Collection<GpsPoint> c : layer.data)
-								for (GpsPoint p : c)
-									if (p.latlon.isWithin(b))
-										gpxPoints.add(p);
-						}
-					}
-				}
-				if (input.contains("all")) {
-					if (addOsm)
-						for (OsmPrimitive osm : Main.ds.allPrimitives())
-							osm.visit(adder);
-					for (Layer l : Main.map.mapView.getAllLayers())
-						if (l instanceof RawGpsLayer)
-							for (Collection<GpsPoint> c : ((RawGpsLayer)l).data)
-								for (GpsPoint p : c)
-									gpxPoints.add(p);
-				}
-				if (input.contains("screen")) {
-					if (Main.map == null) {
-						errorMessage = tr("The Tool requires some data to be loaded.");
-						cancel();
-						return;
-					}
-					LatLon bottomLeft = Main.map.mapView.getLatLon(0,Main.map.mapView.getHeight());
-					LatLon topRight = Main.map.mapView.getLatLon(Main.map.mapView.getWidth(), 0);
-					Bounds b = new Bounds(bottomLeft, topRight);
-					if (addOsm) {
-						Collection<Node> nodes = new HashSet<Node>();
-						for (Node n : Main.ds.nodes) {
-							if (n.coor.isWithin(b)) {
-								n.visit(adder);
-								nodes.add(n);
-							}
-						}
-						Collection<Segment> segments = new HashSet<Segment>();
-						for (Segment s : Main.ds.segments) {
-							if (nodes.contains(s.from) || nodes.contains(s.to)) {
-								s.visit(adder);
-								segments.add(s);
-							}
-						}
-						for (Way w : Main.ds.ways) {
-							for (Segment s : w.segments) {
-								if (segments.contains(s)) {
-									w.visit(adder);
-									break;
-								}
-							}
-						}
-					}
-					if (addGpx) {
-						for (Layer l : Main.map.mapView.getAllLayers())
-							if (l instanceof RawGpsLayer)
-								for (Collection<GpsPoint> c : ((RawGpsLayer)l).data)
-									for (GpsPoint p : c)
-										if (p.latlon.isWithin(b))
-											gpxPoints.add(p);
-					}
-				}
-				OsmWriter.output(p.getOutputStream(), new OsmWriter.Osm(){
-					public void write(PrintWriter out) {
-						if (addOsm)
-							new OsmWriter.All(fromDataSet, false).write(out);
-						if (addGpx) {
-							Collection<Collection<GpsPoint>> c = new LinkedList<Collection<GpsPoint>>();
-							c.add(gpxPoints);
-							GpxWriter.Trk writer = new GpxWriter.Trk(c);
-							writer.header(out);
-							if (!gpxPoints.isEmpty())
-								writer.write(out);
-							writer.footer(out);
-						}
-					}
-				});
-			}
-			if (output != null)
-				dataSet = OsmReader.parseDataSet(p.getInputStream(), Main.ds, Main.pleaseWaitDlg);
-		}
-
-		@Override protected void cancel() {
-			p.destroy();
-		}
-
-		@Override protected void finish() {
-			if (dataSet == null || output == null || output.equals("discard"))
-				return; // user cancelled or no stdout to process
-			Collection<OsmPrimitive> allNew = dataSet.allPrimitives();
-			Collection<OsmPrimitive> allOld = fromDataSet.allPrimitives();
-			if (output.equals("replace")) {
-				Command cmd = createCommand(allOld, allNew);
-				if (cmd != null) {
-					Main.main.editLayer().add(cmd);
-					Main.ds.clearSelection();
-				}
-			} else if (output.equals("selection")) {
-				Collection<OsmPrimitive> sel = new LinkedList<OsmPrimitive>();
-				for (OsmPrimitive osm : Main.ds.allPrimitives())
-					if (allNew.contains(osm))
-						sel.add(osm);
-				Main.ds.setSelected(sel);
-			}
-		}
-
-		/**
-		 * Create a command that replaces all objects in from with those in to. The lists will be
-		 * changed by createCommand.
-		 */
-		private Command createCommand(Collection<OsmPrimitive> from, Collection<OsmPrimitive> to) {
-			// remove all objects in from/to, that are present in both lists.
-			for (Iterator<OsmPrimitive> toIt = to.iterator(); toIt.hasNext();) {
-				OsmPrimitive osm = toIt.next();
-				for (Iterator<OsmPrimitive> fromIt = from.iterator(); fromIt.hasNext();) {
-					if (fromIt.next().realEqual(osm)) {
-						toIt.remove();
-						fromIt.remove();
-						break;
-					}
-				}
-			}
-
-			Collection<Command> cmd = new LinkedList<Command>();
-
-			// extract all objects that have changed
-			for (Iterator<OsmPrimitive> toIt = to.iterator(); toIt.hasNext();) {
-				OsmPrimitive toOsm = toIt.next();
-				for (Iterator<OsmPrimitive> fromIt = from.iterator(); fromIt.hasNext();) {
-					OsmPrimitive fromOsm = fromIt.next();
-					if (fromOsm.equals(toOsm)) {
-						toIt.remove();
-						fromIt.remove();
-						cmd.add(new ChangeCommand(fromOsm, toOsm));
-						break;
-					}
-				}
-			}
-			for (OsmPrimitive fromOsm : Main.ds.allPrimitives()) {
-				for (Iterator<OsmPrimitive> it = to.iterator(); it.hasNext();) {
-					OsmPrimitive toOsm = it.next();
-					if (fromOsm.equals(toOsm)) {
-						it.remove();
-						cmd.add(new ChangeCommand(fromOsm, toOsm));
-						break;
-					}
-				}
-			}
-
-			// extract all added objects
-			for (OsmPrimitive osm : to)
-				cmd.add(new AddCommand(osm));
-
-			// extract all deleted objects. Delete references as well.
-			CollectBackReferencesVisitor v = new CollectBackReferencesVisitor(Main.ds);
-			for (OsmPrimitive osm : from)
-				osm.visit(v);
-			v.data.addAll(from);
-			if (!v.data.isEmpty())
-				cmd.add(new DeleteCommand(v.data));
-
-			if (cmd.isEmpty())
-				return null;
-			return new SequenceCommand(tr("Executing {0}",getValue(NAME)), cmd);
-		}
-	}
-
-	public ExternalToolsAction(String name, String[] exec, String[] flags, String[] input, String output) {
-		super(name);
-		this.exec = exec;
-		this.flags = Arrays.asList(flags);
-		this.input = Arrays.asList(input);
-		this.output = output;
-	}
-
-	public void actionPerformed(ActionEvent e) {
-		try {
-			final Process p = new ProcessBuilder(exec).start();
-			PleaseWaitRunnable runner = new ExecuteToolRunner(tr("Executing {0}",getValue(NAME)), p);
-			Main.worker.execute(runner);
-		} catch (IOException e1) {
-			e1.printStackTrace();
-			JOptionPane.showMessageDialog(Main.parent, tr("Could not execute command: {0}", exec[0]));
-		}
-	}
-
-	/**
-	 * @return All external tools configured so far as array.
-	 */
-	public static JMenu buildMenu() {
-		if (!new File(Main.pref.getPreferencesDir()+"external_tools").exists())
-			return null;
-
-		final JMenu main = new JMenu(tr("Tools"));
-		main.setMnemonic('T');
-		MinML2 parser = new MinML2() {
-			Stack<JMenu> current = new Stack<JMenu>();
-			@Override public void startDocument() {
-				current.push(main);
-			}
-			@Override public void startElement(String ns, String lname, String qname, Attributes a) throws SAXException {
-				if (qname.equals("group")) {
-					JMenu m = current.peek();
-					current.push(new JMenu(a.getValue(("name"))));
-					m.add(current.peek());
-				}
-				if (!qname.equals("tool"))
-					return;
-				String flagValue = a.getValue("flags");
-				String[] flags = flagValue==null ? new String[]{} : flagValue.split(",");
-				String output = a.getValue("out");
-				String[] exec = a.getValue("exec").split(" ");
-				if (exec.length < 1)
-					throw new SAXException("Execute attribute must not be empty");
-				String inValue = a.getValue("in");
-				String[] input = inValue==null ? new String[]{} : inValue.split(",");
-
-				current.peek().add(new ExternalToolsAction(a.getValue("name"), exec, flags, input, output));
-			}
-			@Override public void endElement(String ns, String lname, String qname) {
-				if (qname.equals("group"))
-					current.pop();
-			}
-		};
-		try {
-			parser.parse(new FileReader(Main.pref.getPreferencesDir()+"external_tools"));
-		} catch (Exception e) {
-			e.printStackTrace();
-			JOptionPane.showMessageDialog(Main.parent, tr("Could not read external tool configuration."));
-		}
-		return main;
-	}
-}
Index: src/org/openstreetmap/josm/data/osm/visitor/SimplePaintVisitor.java
===================================================================
--- src/org/openstreetmap/josm/data/osm/visitor/SimplePaintVisitor.java	(revision 163)
+++ src/org/openstreetmap/josm/data/osm/visitor/SimplePaintVisitor.java	(revision 167)
@@ -6,5 +6,7 @@
 
 import org.openstreetmap.josm.Main;
+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.Segment;
 import org.openstreetmap.josm.data.osm.Way;
@@ -34,4 +36,19 @@
 
 	protected static final double PHI = Math.toRadians(20);
+
+	public void visitAll(DataSet data) {
+		for (final OsmPrimitive osm : data.segments)
+			if (!osm.deleted)
+				osm.visit(this);
+		for (final OsmPrimitive osm : data.ways)
+			if (!osm.deleted)
+				osm.visit(this);
+		for (final OsmPrimitive osm : data.nodes)
+			if (!osm.deleted)
+				osm.visit(this);
+		for (final OsmPrimitive osm : data.getSelected())
+			if (!osm.deleted)
+				osm.visit(this);
+	}
 
 	/**
Index: src/org/openstreetmap/josm/gui/MainMenu.java
===================================================================
--- src/org/openstreetmap/josm/gui/MainMenu.java	(revision 163)
+++ src/org/openstreetmap/josm/gui/MainMenu.java	(revision 167)
@@ -10,8 +10,8 @@
 import org.openstreetmap.josm.actions.AboutAction;
 import org.openstreetmap.josm.actions.AlignInCircleAction;
+import org.openstreetmap.josm.actions.AlignInLineAction;
 import org.openstreetmap.josm.actions.DownloadAction;
 import org.openstreetmap.josm.actions.DownloadIncompleteAction;
 import org.openstreetmap.josm.actions.ExitAction;
-import org.openstreetmap.josm.actions.ExternalToolsAction;
 import org.openstreetmap.josm.actions.GpxExportAction;
 import org.openstreetmap.josm.actions.HelpAction;
@@ -41,4 +41,5 @@
 	public final Action reverseSegment = new ReverseSegmentAction();
 	public final Action alignInCircle = new AlignInCircleAction();
+	public final Action alignInLine = new AlignInLineAction();
 	public final Action upload = new UploadAction();
 	public final Action save = new SaveAction();
@@ -52,5 +53,4 @@
 	public final JMenu layerMenu = new JMenu(tr("Layer"));
 	public final JMenu editMenu = new JMenu(tr("Edit"));
-	public final JMenu externalMenu = ExternalToolsAction.buildMenu();
 	public final JMenu helpMenu = new JMenu(tr("Help"));
 	public final JMenu fileMenu = new JMenu(tr("Files"));
@@ -76,4 +76,5 @@
 		editMenu.add(reverseSegment);
 		editMenu.add(alignInCircle);
+		editMenu.add(alignInLine);
 		editMenu.addSeparator();
 		editMenu.add(preferences);
@@ -90,10 +91,6 @@
 		layerMenu.setVisible(false);
 
+		add(Box.createHorizontalGlue());
 
-		if (externalMenu != null)
-			add(externalMenu);
-
-		add(Box.createHorizontalGlue());
-		
 		helpMenu.setMnemonic('H');
 		helpMenu.add(help);
Index: src/org/openstreetmap/josm/gui/MapFrame.java
===================================================================
--- src/org/openstreetmap/josm/gui/MapFrame.java	(revision 163)
+++ src/org/openstreetmap/josm/gui/MapFrame.java	(revision 167)
@@ -58,8 +58,10 @@
 	 */
 	public MapStatus statusLine;
-	
+
 	public ConflictDialog conflictDialog;
 	private JPanel toggleDialogs = new JPanel();
-	
+
+	public final ButtonGroup toolGroup = new ButtonGroup();
+
 	/**
 	 * Construct a map with a given DataSet. The set cannot be replaced after 
@@ -87,6 +89,4 @@
 		toolBarActions.add(new IconToggleButton(new DeleteAction(this)));
 
-		// all map modes in one button group
-		ButtonGroup toolGroup = new ButtonGroup();
 		for (Component c : toolBarActions.getComponents())
 			toolGroup.add((AbstractButton)c);
@@ -112,5 +112,5 @@
 				if (!autoScaleButton.groupbutton)
 					autoScaleButton.setSelected(true);
-            }
+			}
 		});
 
@@ -130,6 +130,6 @@
 
 	public Action getDefaultButtonAction() {
-	    return ((AbstractButton)toolBarActions.getComponent(0)).getAction();
-    }
+		return ((AbstractButton)toolBarActions.getComponent(0)).getAction();
+	}
 
 	/**
@@ -147,11 +147,11 @@
 
 	private void addIconToggle(JPanel toggleDialogs, ToggleDialog dlg) {
-        IconToggleButton button = new IconToggleButton(dlg.action);
-        dlg.action.button = button;
+		IconToggleButton button = new IconToggleButton(dlg.action);
+		dlg.action.button = button;
 		toolBarActions.add(button);
 		toggleDialogs.add(dlg);
 	}
 
-	
+
 	/**
 	 * Fires an property changed event "visible".
Index: src/org/openstreetmap/josm/gui/annotation/AnnotationPreset.java
===================================================================
--- src/org/openstreetmap/josm/gui/annotation/AnnotationPreset.java	(revision 163)
+++ src/org/openstreetmap/josm/gui/annotation/AnnotationPreset.java	(revision 167)
@@ -46,7 +46,8 @@
 
 	public static class Text implements Item {
-		String key;
-		String label;
-		JTextField value = new JTextField();
+		private String key;
+		private String label;
+		private JTextField value = new JTextField();
+		private boolean deleteIfEmpty;
 
 		public void addToPanel(JPanel p) {
@@ -54,17 +55,21 @@
 			p.add(value, GBC.eol().fill(GBC.HORIZONTAL));
 		}
-		public Text(String key, String label, String value) {
+		public Text(String key, String label, String value, boolean deleteIfEmpty) {
 			this.key = key;
 			this.label = label;
 			this.value.setText(value == null ? "" : value);
-		}
-		public void addCommands(Collection<OsmPrimitive> sel, List<Command> cmds) {
-			cmds.add(new ChangePropertyCommand(sel, key, value.getText()));
+			this.deleteIfEmpty = deleteIfEmpty;
+		}
+		public void addCommands(Collection<OsmPrimitive> sel, List<Command> cmds) {
+			String v = value.getText();
+			if (deleteIfEmpty && v.length() == 0)
+				v = null;
+			cmds.add(new ChangePropertyCommand(sel, key, v));
 		}
 	}
 
 	public static class Check implements Item {
-		String key;
-		JCheckBox check = new JCheckBox();
+		private String key;
+		private JCheckBox check = new JCheckBox();
 
 		public void addToPanel(JPanel p) {
@@ -82,8 +87,9 @@
 
 	public static class Combo implements Item {
-		String key;
-		String label;
-		JComboBox combo;
+		private String key;
+		private String label;
+		private JComboBox combo;
 		private final String[] values;
+		private boolean deleteIfEmpty;
 
 		public void addToPanel(JPanel p) {
@@ -91,8 +97,9 @@
 			p.add(combo, GBC.eol().fill(GBC.HORIZONTAL));
 		}
-		public Combo(String key, String label, String def, String[] values, String[] displayedValues, boolean editable) {
+		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);
@@ -102,4 +109,6 @@
 			String v = combo.getSelectedIndex() == -1 ? null : values[combo.getSelectedIndex()];
 			String str = combo.isEditable()?combo.getEditor().getItem().toString() : v;
+			if (deleteIfEmpty && str != null && str.length() == 0)
+				str = null;
 			cmds.add(new ChangePropertyCommand(sel, key, str));
 		}
@@ -107,5 +116,5 @@
 
 	public static class Label implements Item {
-		String text;
+		private String text;
 
 		public void addToPanel(JPanel p) {
@@ -119,6 +128,6 @@
 
 	public static class Key implements Item {
-		String key;
-		String value;
+		private String key;
+		private String value;
 
 		public void addToPanel(JPanel p) {}
@@ -162,8 +171,8 @@
 				}
 			} else if (qname.equals("text"))
-				current.add(new Text(a.getValue("key"), a.getValue("text"), a.getValue("default")));
+				current.add(new Text(a.getValue("key"), a.getValue("text"), a.getValue("default"), parseBoolean(a.getValue("delete_if_empty"))));
 			else if (qname.equals("check")) {
 				String s = a.getValue("default");
-				boolean clear = s == null || s.equals("0") || s.startsWith("off") || s.startsWith("false") || s.startsWith("no");
+				boolean clear = parseBoolean(s);
 				current.add(new Check(a.getValue("key"), a.getValue("text"), !clear));
 			} else if (qname.equals("label"))
@@ -173,5 +182,5 @@
 				String s = a.getValue("readonly");
 				String dvstr = a.getValue("display_values");
-				boolean editable = s == null  || s.equals("0") || s.startsWith("off") || s.startsWith("false") || s.startsWith("no");
+				boolean editable = parseBoolean(s);
 				if (dvstr != null) {
 					if (editable && s != null)
@@ -184,5 +193,5 @@
 							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));
+				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")));
@@ -190,4 +199,8 @@
 				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) {
Index: src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java
===================================================================
--- src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 163)
+++ src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java	(revision 167)
@@ -142,16 +142,5 @@
 		mapPainter.setGraphics(g);
 		mapPainter.setNavigatableComponent(mv);
-		for (final OsmPrimitive osm : data.segments)
-			if (!osm.deleted)
-				osm.visit(mapPainter);
-		for (final OsmPrimitive osm : data.ways)
-			if (!osm.deleted)
-				osm.visit(mapPainter);
-		for (final OsmPrimitive osm : data.nodes)
-			if (!osm.deleted)
-				osm.visit(mapPainter);
-		for (final OsmPrimitive osm : data.getSelected())
-			if (!osm.deleted)
-				osm.visit(mapPainter);
+		mapPainter.visitAll(data);
 		Main.map.conflictDialog.paintConflicts(g, mv);
 	}
Index: src/org/openstreetmap/josm/io/OsmWriter.java
===================================================================
--- src/org/openstreetmap/josm/io/OsmWriter.java	(revision 163)
+++ src/org/openstreetmap/josm/io/OsmWriter.java	(revision 167)
@@ -62,9 +62,16 @@
 			Visitor writer = new OsmWriter(out, osmConform);
 			for (Node n : ds.nodes)
-				writer.visit(n);
+				if (shouldWrite(n))
+					writer.visit(n);
 			for (Segment ls : ds.segments)
-				writer.visit(ls);
+				if (shouldWrite(ls))
+					writer.visit(ls);
 			for (Way w : ds.ways)
-				writer.visit(w);
+				if (shouldWrite(w))
+					writer.visit(w);
+        }
+
+		private boolean shouldWrite(OsmPrimitive osm) {
+	        return osm.id != 0 || !osm.deleted;
         }
 	}
Index: src/org/openstreetmap/josm/plugins/PluginInformation.java
===================================================================
--- src/org/openstreetmap/josm/plugins/PluginInformation.java	(revision 163)
+++ src/org/openstreetmap/josm/plugins/PluginInformation.java	(revision 167)
@@ -6,4 +6,6 @@
 import java.net.URL;
 import java.net.URLClassLoader;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Map;
 import java.util.TreeMap;
@@ -25,7 +27,11 @@
 	public final boolean early;
 	public final String author;
+	public final List<URL> libraries = new ArrayList<URL>();
 
 	public final Map<String, String> attr = new TreeMap<String, String>();
 
+	/**
+	 * @param file the plugin jar file.
+	 */
 	public PluginInformation(File file) {
 		this.file = file;
@@ -39,4 +45,14 @@
 			early = Boolean.parseBoolean(attr.getValue("Plugin-Early"));
 			author = attr.getValue("Author");
+			libraries.add(new URL(getURLString(file.getAbsolutePath())));
+			String classPath = attr.getValue("Class-Path");
+			if (classPath != null) {
+				for (String s : classPath.split(classPath.contains(";") ? ";" : ":")) {
+					if (!s.startsWith("/") && !s.startsWith("\\") && !s.matches("^.:"))
+						s = file.getParent() + File.separator + s;
+					libraries.add(new URL(getURLString(s)));
+				}
+			}
+
 			for (Object o : attr.keySet())
 				this.attr.put(o.toString(), attr.getValue(o.toString()));
@@ -63,7 +79,7 @@
 	public Class<?> loadClass() {
 		try {
-			ClassLoader loader = URLClassLoader.newInstance(
-					new URL[]{new URL(getURLString())},
-					getClass().getClassLoader());
+			URL[] urls = new URL[libraries.size()];
+			urls = libraries.toArray(urls);
+			ClassLoader loader = URLClassLoader.newInstance(urls, getClass().getClassLoader());
 			Class<?> realClass = Class.forName(className, true, loader);
 			return realClass;
@@ -73,8 +89,8 @@
 	}
 
-	private String getURLString() {
+	private String getURLString(String fileName) {
 		if (System.getProperty("os.name").startsWith("Windows"))
-			return "file:/"+file.getAbsolutePath();
-		return "file://"+file.getAbsolutePath();
+			return "file:/"+fileName;
+		return "file://"+fileName;
 	}
 }
Index: src/org/openstreetmap/josm/tools/WikiReader.java
===================================================================
--- src/org/openstreetmap/josm/tools/WikiReader.java	(revision 163)
+++ src/org/openstreetmap/josm/tools/WikiReader.java	(revision 167)
@@ -4,5 +4,4 @@
 import java.io.IOException;
 import java.io.InputStreamReader;
-import java.net.MalformedURLException;
 import java.net.URL;
 
@@ -27,18 +26,12 @@
 	 * replace relative pathes etc..
 	 *
-	 * @return Either the string of the content of the wiki page or <code>null</code>
-	 * if the page could not be read.
+	 * @return Either the string of the content of the wiki page.
+	 * @throws IOException Throws, if the page could not be loaded.
 	 */
-	public String read(String url) {
-		try {
-	        BufferedReader in = new BufferedReader(new InputStreamReader(new URL(url).openStream()));
-	        if (url.startsWith(baseurl))
-	        	return readFromTrac(in, url);
-	        return readNormal(in);
-        } catch (MalformedURLException e) {
-        	throw new RuntimeException(e);
-        } catch (IOException e) {
-        	return null;
-        }
+	public String read(String url) throws IOException {
+        BufferedReader in = new BufferedReader(new InputStreamReader(new URL(url).openStream()));
+        if (url.startsWith(baseurl))
+        	return readFromTrac(in, url);
+        return readNormal(in);
 	}
 
